Adopt @exadev/eslint-config - #22
Merged
Merged
Conversation
Adds @exadev/eslint-config as an exact-pinned dev dependency and excludes it from the minimum-release-age gate, since it is a first-party ExaDev package. Also bumps the pinned package manager to pnpm 12.4.1 and turns on saveExact so future dependency additions resolve to exact versions rather than caret ranges.
Replaces the hand-rolled flat config (js.configs.recommended plus the tseslint presets, a local no-pointless-reassignment rule, and a manual re-export ban) with the shared @exadev/eslint-config array, which already covers all of the same ground plus stricter rules this repo wasn't previously enforcing. Also switches from tseslint.config, which typescript-eslint itself now flags as deprecated, to defineConfig from eslint/config. The custom local/no-pointless-reassignment rule and its eslint-rules/ directory are removed entirely, superseded by the equivalent exadev/no-pointless-reassignment rule the shared config already includes.
Rewrites scripts/stamp-schema-ids.mjs as stamp-schema-ids.mts with real types throughout: an isRecord type guard replaces an `as` cast, resolveTag and main both carry explicit return types. This also removes the need for eslint.config.ts's own allowDefaultProject fallback, since the file is no longer a plain untyped script excluded from the type-aware project service. Updates every reference to the old .mjs path (the CI workflow, gen-schema-core.ts, README.md).
The diagnostic-dedup key template literal in src/resolve/decide.ts contained literal NUL bytes standing in for the spaces between segments, syntactically valid to tsc/ESLint but not what the code was meant to do. Replaces them with real spaces and wraps the numeric layer values with String() so the same line also satisfies restrict-template-expressions.
Fixes the resolver module's own lint violations under the newly adopted shared config: numeric template-literal interpolations wrapped in String(), magic-number literals extracted into named constants describing what they represent, a readonly parameter annotation, and a provably-unreachable undefined check removed from flattenLayers now that CategoryMap's own type already guarantees a present entry is a boolean.
Fixes the launcher module's own lint violations under the newly adopted shared config. Notably, refactors listSubtree in farm.ts from a readonly out-parameter callers were pushing into (a real pre-existing type error, masked until now by a stale tsconfig.tsbuildinfo) into a pure function returning a new array via flatMap; removes a provably dead os.constants.signals undefined branch in spawn.ts, since that mapping is closed over every NodeJS.Signals name; replaces non-null-assertion index reads with explicit undefined guards throughout; and extracts magic-number literals into named constants.
Fixes config module violations: schema.test.ts derives its toHaveLength assertion from the actual rules array instead of a hardcoded count, store.test.ts replaces a non-null-assertion index read with an explicit undefined guard, and store.ts/load.ts pick up the same numeric-template and magic-number fixes as elsewhere.
Adds a default: return target satisfies never; branch to describeWriteTarget's switch (an exhaustive switch with no default still needs one for consistent-return, since TypeScript's own exhaustiveness proof doesn't satisfy the rule), replaces non-null-assertion index reads in configure.ts and directoryRules.ts with explicit undefined guards, adds braces to void-return arrow shorthands in configure.test.ts, and fixes a template already reading an already-narrowed local instead of re-reading the wider option.
Adds a default: return severity satisfies never; branch to severityPrefix's switch and a String() wrap for a numeric template interpolation in doctor.ts; simplifies doctor.test.ts's report assertions by dropping the let-plus-not.toThrow()-plus-repeated-! pattern in favour of a plain const, since an uncaught throw already fails the test; and adds a proper compare function to a .sort() call that previously relied on default lexicographic ordering.
Adds an EXECUTABLE_FILE_MODE named constant for the 0o755 permission
bits shared by claudeShim.ts and its tests, replaces two
Object.assign(new Error(...), { code }) calls in
claudeShim.test.ts with a proper CodedError subclass (exadev bans
Object.assign for this), rewords a TSDoc arrow in cli/parsers.ts, and
extracts a named constant for a magic PID literal in cliError.test.ts.
Fixes check.ts's numeric template interpolations, paths.test.ts's non-null assertion, realPorts.ts/test.ts and versionDiscovery.ts's TSDoc escaping, and test-helpers.ts/vitest.config.ts's magic-number and void-return-arrow violations, matching the pattern already applied across the rest of the codebase.
…onfig
Backtick-wraps package names and rewords -> arrows in release.config.ts's
TSDoc, extracts named constants for build.mts's magic numbers
(MIN_BUILD_SEA_NODE_MAJOR/MINOR, EXECUTABLE_FILE_MODE,
BYTES_PER_KIB/MIB), and adds a currentNodeMajor() helper in
gen-schema.mts with an explicit undefined guard in place of an inline
process.versions.node.split(".")[0] index read.
@eslint/js is no longer imported directly now that eslint.config.ts gets it transitively through @exadev/eslint-config, and knip.config.ts still listed eslint-rules/**/*.ts as a project pattern after that directory was removed. Both were left over from the eslint-config adoption and knip correctly flagged them.
Mearman
marked this pull request as ready for review
September 14, 2026 16:09
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@exadev/eslint-configas an exact-pinned dependency, replacing the hand-rolled flat config (js.configs.recommended + tseslint presets + a local no-pointless-reassignment rule + a manual re-export ban), all of which the shared config already covers.tseslint.config(now deprecated by typescript-eslint itself) todefineConfigfromeslint/config.scripts/stamp-schema-ids.mjsto real TypeScript (.mts), removing the need for the oldallowDefaultProjectcarve-out.farm.ts'slistSubtree(a readonly array parameter callers were pushing into, previously masked by a staletsconfig.tsbuildinfo).src/resolve/decide.tshad literal NUL bytes standing in for spaces inside a template literal, syntactically valid but clearly unintended.Test plan
pnpm lintcleanpnpm exec tsc --noEmitclean (verified with a fresh tsbuildinfo)pnpm test— 804 tests passing