Skip to content

Add prefer-options-object-param rule and tune max-params - #28

Merged
Mearman merged 4 commits into
mainfrom
feat/prefer-options-object-param
Sep 19, 2026
Merged

Mearman merged 4 commits into
mainfrom
feat/prefer-options-object-param

Conversation

@Mearman

@Mearman Mearman commented Sep 19, 2026

Copy link
Copy Markdown
Member

Summary

Adds a new custom rule, exadev/prefer-options-object-param, that detects a run of 2+ trailing optional parameters and suggests bundling them into a single destructured options parameter — the motivating case is a constructor/function where a caller needing only the last optional parameter has to pass undefined for every one before it.

Also tunes core max-params to { max: 4 } (one above its own default) in both bundles, as a deliberately loose backstop against a genuinely excessive number of required parameters — a shape the new rule is structurally blind to, since it only looks at the trailing optional run.

Changes

  • exadev/prefer-options-object-param: type-aware in placement only (see the rule's own file header) — every check and every fix is purely syntactic, using verbatim source-text slices rather than checker-based type reconstruction. Uses hasSuggestions, not a silent fixable, since the fix rewrites both a parameter list and the function body. Registered only in the type-checked bundle, alongside prefer-readonly-object-param/prefer-numeric-sort-compare.
  • max-params at { max: 4 }, registered in both plugin.configs.recommended and the type-checked bundle (needs no type info).
  • no-non-barrel-reexport.ts: removeListMember had 5 required parameters, tripping the newly-enabled max-params. Bundled its always-together fixer/sourceCode pair into one FixerContext parameter — a genuine reduction, not a workaround.
  • ts-node-guards.ts: added firstTokenOrThrow, the first-token mirror of the existing lastTokenOrThrow, used by the new rule's fixer.
  • README updated (rules table, bullet list, individual rule tuning section).

Test plan

  • pnpm test — full suite green (805 tests), including 33 new tests for the rule covering every valid/invalid case and every bail-out named in the design (parameter property, missing name/type, decorated parameter, rest parameter anywhere in the list, no block body — arrow expression body / declaration-only signatures / .d.ts, @param JSDoc mention, options-name collision), plus the real WireMeshTransport constructor shape as a permanent regression case.
  • pnpm typecheck — clean.
  • pnpm lint — clean.
  • pnpm build — clean.
  • Manually verified against a real build (dist/) run through a real Linter, against the exact WireMeshTransport constructor shape: the rule reports and the suggested fix's output was confirmed against tsc --strict — the new options-based call site typechecks cleanly, and the old stale positional call site fails with a real TS2554 "Expected 2-3 arguments, but got 10" error.

…text param

removeListMember took 5 required parameters, tripping this repo's own
max-params threshold. fixer and sourceCode were always passed together
at every call site, so grouping them into one FixerContext parameter
is a genuine reduction, not a workaround.
The first-token mirror of the existing lastTokenOrThrow, for the
identical reason: getFirstToken only ever returns null for a node
with genuinely no tokens at all, never true of a real AST node this
codebase's own rules call it on.
Detects a run of 2+ trailing optional parameters ('?'-marked or
default-valued) and suggests bundling them into a single destructured
'options' parameter. Without this, a caller needing only the last
optional parameter must still pass 'undefined' for every optional
parameter before it.

Uses hasSuggestions rather than a silent fixable autofix, since the
fix rewrites both a parameter list and the function body. Every
type-text extraction is a verbatim source-text slice rather than a
checker-based reconstruction, so the rule needs no type information
at all despite living in the type-checked bundle.

Reports but withholds the suggestion whenever collapsing the run
would not be safe or mechanical: a parameter property, a parameter
with no simple resolvable name and explicit type of its own, a
decorated parameter, a rest parameter anywhere in the parameter list,
no block body at all (an arrow's expression body or any
declaration-only signature), a '@PARAM' JSDoc tag naming a parameter
in the run, or a parameter/local variable already named 'options'.
Registers exadev/prefer-options-object-param in the type-checked
bundle only, alongside prefer-readonly-object-param and
prefer-numeric-sort-compare, for a consistent "every rewrite-
suggestion prefer-* rule lives here" story even though it needs no
type information itself.

Adds core max-params at { max: 4 }, one above its own default, to
both plugin.configs.recommended and the type-checked bundle. It is a
deliberately loose backstop against excessive REQUIRED parameters, a
shape prefer-options-object-param is structurally blind to since it
only ever looks at trailing OPTIONAL parameters.

Documents both in the README.
@Mearman
Mearman marked this pull request as ready for review September 19, 2026 09:55
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 19, 2026 •

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-19T09:59:16.483352Z a443d12 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.

@Mearman
Mearman merged commit 2fbaf46 into main Sep 19, 2026
6 checks passed
@Mearman
Mearman deleted the feat/prefer-options-object-param branch September 19, 2026 09:56
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 2.20.0 🎉

The release is available on:

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