Skip to content

Adopt @exadev/eslint-config - #68

Merged
Mearman merged 3 commits into
mainfrom
feat/adopt-exadev-eslint-config
Sep 14, 2026
Merged

Mearman merged 3 commits into
mainfrom
feat/adopt-exadev-eslint-config

Conversation

@Mearman

@Mearman Mearman commented Sep 14, 2026

Copy link
Copy Markdown
Member

Summary

  • Adopts @exadev/eslint-config@2.12.3 as an exact-pinned dev dependency, replacing tseslint.configs.recommended (which carried no type information) with the shared type-checked config array.
  • Bumps the pinned package manager to npm 12.0.2, and approves @anthropic-ai/claude-code's postinstall script, which npm 12's lifecycle-script gate now blocks by default — the dependabot investigate job invokes this CLI directly via npx, so the script genuinely needs to run.
  • Converts the two semantic-release plugin scripts referenced by path from release.config.ts (format-changelog.mjs, move-major-tag.mjs) to real TypeScript (.mts), typed against semantic-release's own exported PrepareContext/SuccessContext. Both scripts' logger field resolves unsafely because the signale package they depend on ships no type declarations at all and skipLibCheck hides the gap from tsc — overridden with a narrow, honest local type for just the log method each script actually calls, rather than accepting the effectively-any upstream type. Also fixes a genuine noUncheckedIndexedAccess gap (nextRelease.version.split(".")[0] is string | undefined) with an explicit guard.
  • Fixes a real gap the .mts conversion would otherwise have introduced silently: lint-staged.config.ts's "*.{ts,md}" glob never matched a .mts file, so these two scripts would have bypassed pre-commit lint/format on every future edit. Widened to "*.{ts,mts,md}".
  • Updates every reference to the old .mjs paths (release.config.ts, the CI workflow, README.md).

Test plan

  • npm run lint clean
  • npm run typecheck clean
  • npm run format:check clean
  • actionlint clean (no action.yml/workflow behavioural changes)

Adds @exadev/eslint-config as an exact-pinned dev dependency, and
bumps the pinned package manager to npm 12.0.2. Also approves
@anthropic-ai/claude-code's postinstall script, which npm 12's
lifecycle-script gate now blocks by default -- the dependabot
investigate job invokes this CLI directly via npx, so the script
genuinely needs to run.
Adopts @exadev/eslint-config's type-checked ruleset (replacing the
previous tseslint.configs.recommended, which carried no type
information at all) and fixes the resulting fallout in the two
semantic-release plugin scripts it referenced by path,
format-changelog.mjs and move-major-tag.mjs: both had no type
annotations, and eslint's type-checked rules crashed outright on a
plain .mjs file with no parserOptions/project configured for it.

Converts both to real TypeScript (.mts), typed against
semantic-release's own exported PrepareContext/SuccessContext, and
adds scripts/**/*.mts to tsconfig.json's include so they get real
type-checking. Both types' logger field resolves unsafely, since the
signale package they depend on ships no type declarations of its own
and skipLibCheck hides the resulting gap from tsc -- overridden with
a narrow, honest local type for just the log method each script
actually calls, rather than accepting the effectively-any upstream
type. Also fixes a genuine noUncheckedIndexedAccess gap in
move-major-tag.mts (nextRelease.version.split(".")[0] is
string | undefined) with an explicit guard, and drops the unneeded
async from a function that never awaits.

Updates every reference to the old .mjs paths (release.config.ts,
the CI workflow, README.md).
lint-staged.config.ts's "*.{ts,md}" pattern never matched a .mts
file, so the two semantic-release plugin scripts just converted from
.mjs would have silently bypassed pre-commit eslint/prettier on every
future edit. Widens the pattern to "*.{ts,mts,md}".
@Mearman
Mearman marked this pull request as ready for review September 14, 2026 17:42
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-14T17:47:23.470106Z 32e169e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-verified adoption of @exadev/eslint-config. Cross-checked every non-trivial claim against upstream sources rather than taking the PR description at face value:

  • eslint.config.ts's new structure (parser-options block before ...exadev) matches the package's own documented consumer pattern exactly, and its internal file-matching glob (**/*.mts included) confirms the renamed plugin scripts get type-checked linting.
  • package.json's new allowScripts entry is a real npm 12 feature, and the one entry present (@anthropic-ai/claude-code@2.1.259) is exactly the only package in package-lock.json with hasInstallScript: true — nothing missing, nothing extraneous.
  • TypedPrepareContext/TypedSuccessContext correctly narrow semantic-release's real PrepareContext/SuccessContext exports, and the rationale (signale ships no type declarations) checks out.
  • The noUncheckedIndexedAccess guard in move-major-tag.mts (majorVersionSegment === undefined) and the cwd ?? process.cwd() fix in format-changelog.mts are both correctly typed against the real upstream shapes.
  • lint-staged.config.ts's .mts glob addition is a genuine bug fix — without it the renamed plugin files would silently skip pre-commit lint/format. No other config in the repo has the same blind spot.
  • No stale .mjs references remain anywhere.

One Nit inline: no CI coverage exercises the newly-renamed .mts semantic-release plugins before an actual push-to-main release attempt — worth a local dry-run before merging, not blocking.

Context: PR #67 (Dependabot bump of @types/node/eslint/lint-staged/typescript) touches the same package.json/package-lock.json — whichever merges first will need the other rebased. No related open issues found to reference. No prior reviews/comments existed on this PR.

Disclosure: sandboxed execution in this run couldn't reach the network for npm install/npm run lint/typecheck/format:check, so verification above relied on reading upstream sources (semantic-release's own .d.ts, @exadev/eslint-config's README and source, npm's release notes) via gh api/WebFetch rather than running the toolchain directly.

Comment thread release.config.ts

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reviews commit 32e169e (the current HEAD), which already carries an identical APPROVED review from this same bot at this exact commit — nothing has changed since, so this pass is a re-verification rather than a fresh look. Not treating the prior review as stale/superseded: dismissal applies to a review left on an earlier commit a new push has addressed, and there is no newer commit here.

Independently checked: eslint.config.ts, tsconfig.json, the package.json/package-lock.json diff, the .mjs.mts conversions (format-changelog.mts, move-major-tag.mts), lint-staged.config.ts, .npmrc, and the CI/README reference updates. No new correctness, security, or compatibility issues beyond what the prior review already raised.

Re-verified the one open finding still holds — 🟡 Nit [stack-default] on release.config.ts:76: confirmed via .github/workflows/ci.yml that the release job (the only place semantic-release actually executes, and therefore the only place Node's native .mts type-stripping for these plugin files is exercised) runs solely on: push to main (if: ... && github.event_name == 'push'), never on a pull request. That thread stays open, since nothing in this commit addresses it — worth a local npx semantic-release --dry-run (or otherwise exercising this branch's own plugin files) before merge, as the prior review suggested.

Also checked: semantic-release 25.0.9's own published type declarations show PrepareContext/SuccessContext.cwd as string | undefined on both types, so format-changelog.mts's cwd ?? process.cwd() fallback is correct and necessary there (used in a plain join(), which doesn't otherwise handle undefined). move-major-tag.mts passing cwd straight into execFileSync's options needs no equivalent fallback — Node's child_process cwd option already treats undefined as "use the parent process's own cwd" — so this isn't an inconsistency between the two files.

Title and description are already complete and grounded in the diff; left unchanged.

No blocking issues. Approving.

@github-actions

Copy link
Copy Markdown

🗜️ Headroom context compression

Metric Value
Requests proxied 77
Tokens saved 219888
Aggregate savings 2.0% of all tokens sent
Average per-request compression 2.7%

@Mearman
Mearman merged commit 6129db6 into main Sep 14, 2026
18 checks passed
@Mearman
Mearman deleted the feat/adopt-exadev-eslint-config branch September 14, 2026 17:59
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.12.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant