Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

feat(lint): add useMemberOrdering nursery rule#9042

Open
thilllon wants to merge 6 commits intobiomejs:mainfrom
thilllon:member-ordering
Open

feat(lint): add useMemberOrdering nursery rule#9042
thilllon wants to merge 6 commits intobiomejs:mainfrom
thilllon:member-ordering

Conversation

@thilllon
Copy link

Summary

  • Added a new nursery lint rule useMemberOrdering that enforces a consistent ordering of class members, corresponding to ESLint TypeScript's @typescript-eslint/member-ordering.
  • The rule supports a fully configurable groups option with 40+ member categories (properties, methods, accessors, constructors, static blocks, with static/accessibility/hash-private variations).
  • Default order: index signatures → static properties → instance properties → static accessors → instance accessors → static methods → constructor → instance methods → static blocks.

Details

New files

  • crates/biome_rule_options/src/use_member_ordering.rsMemberGroup enum and UseMemberOrderingOptions struct
  • crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs — Rule implementation with classify_member() for all AnyJsClassMember variants

Modified files

  • crates/biome_diagnostics_categories/src/categories.rs — Added category entry
  • crates/biome_rule_options/src/lib.rs — Registered module
  • crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs — Added @typescript-eslint/member-ordering migration mapping

Tests

  • valid.js / valid.ts — Correct ordering cases (no diagnostics)
  • invalid.js / invalid.ts — Incorrect ordering cases (diagnostics expected)
  • customOrder.js + customOrder.options.json — Custom group order via options

Test plan

  • cargo t use_member_ordering — 6 tests pass
  • cargo fmt — No formatting issues
  • Snapshot tests accepted via cargo insta accept

AI assistance disclosure

This PR was written primarily with AI assistance (Cursor + Claude).

Made with Cursor

@changeset-bot
Copy link

changeset-bot bot commented Feb 12, 2026

🦋 Changeset detected

Latest commit: 8d96045

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added A-CLI Area: CLI A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Feb 12, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new nursery lint rule useMemberOrdering that enforces configurable class member ordering for JavaScript and TypeScript. Implements the rule, member classification (including static, accessibility and hash-private categories), violation detection, diagnostics, options handling, and defaults. Adds corresponding rule options types, serialization, and a comprehensive suite of test fixtures (valid/invalid and custom-order cases). Also adds documentation for the rule and exposes UseMemberOrdering and MemberOrderViolation publicly.

Suggested reviewers

  • dyc3
  • ematipico
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely describes the main change: adding a new nursery lint rule for enforcing member ordering in classes.
Description check ✅ Passed The PR description comprehensively details the new rule, its configuration options, affected files, test coverage, and validation steps—all directly related to the changeset.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@thilllon
Copy link
Author

@coderabbitai review

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs`:
- Around line 90-96: The diagnostic currently emits a hardcoded note in the
.note(markup! { "Members should be ordered by: properties, constructors,
methods." }) call which is misleading for non-default or user-configured orders;
update the code in use_member_ordering.rs to either remove this static note or
build the note text dynamically from the active ordering settings (the rule's
configured order) and use that generated string in the .note(...) invocation
(refer to the place where .note(markup! { ... }) is called and the state/options
that contain the ordering to compose the message).
- Line 54: The rule registration currently uses
RuleSource::EslintTypeScript("member-ordering").same() which incorrectly claims
identical behavior; change it to
RuleSource::EslintTypeScript("member-ordering").inspired() to indicate we only
mirror some class-member ordering behavior (not full
interface/type/enum/memberTypes/optionalityOrder/order support). Update the
entry where sources: &[RuleSource::EslintTypeScript("member-ordering").same()]
is defined to use .inspired() so the rule source accurately reflects
partial/modified behavior.
- Around line 427-451: In find_order_violations, prev_rank currently stores the
last seen member's rank which lets lower-ranked violating members lower the
baseline and mask later violations; change the logic so prev_rank tracks the
maximum rank seen so far (and its label) instead of the immediate predecessor:
when you compute rank = group.rank(order), if rank < prev_r push the
MemberOrderViolation (using member_range and expected_before_name), but do NOT
set prev_rank to the lower rank—instead set prev_rank = Some((max(prev_r, rank),
label_for_max)) so prev_rank always holds the highest rank and its corresponding
label; update references to prev_label/prev_r accordingly in the loop.
🧹 Nitpick comments (2)
crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs (1)

102-229: Accessor / StaticAccessor / etc. groups are in default_order() but never classified.

classify_member maps getters → GetAccessor* and setters → SetAccessor*, but never returns the combined Accessor* variants. Those combined groups occupy rank positions in the default order, effectively acting as dead slots. This isn't a bug per se, but it means the combined accessor groups are only useful in custom configurations, which could confuse users expecting them to work out of the box.

Consider either documenting this clearly or removing the combined accessor entries from default_order().

crates/biome_rule_options/src/use_member_ordering.rs (1)

134-192: default_order() allocates a new Vec on every call — consider a static slice.

groups() calls default_order() which builds a fresh 44-element Vec each time. Since the default never changes, a &'static [MemberGroup] constant would avoid the allocation entirely and let groups() return a Vec only when the user provides a custom order.

Not urgent — this is called once per class — but it's a tidy improvement.

Sketch
const DEFAULT_ORDER: &[MemberGroup] = &[
    MemberGroup::IndexSignature,
    MemberGroup::StaticIndexSignature,
    // ... all variants ...
    MemberGroup::StaticBlock,
];

impl MemberGroup {
    pub fn default_order() -> &'static [MemberGroup] {
        DEFAULT_ORDER
    }
}

Then adjust groups() and rank() signatures to accept &[MemberGroup] (which they already do on the consumer side).

@thilllon
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs`:
- Around line 88-100: The current deduplication uses
label.split_whitespace().last() which truncates meaningful group names (symbols:
seen, order, label, broad, order_description) — change this to use the full
group label (or map each MemberGroup variant to an explicit, human-friendly
broad category) and dedupe while preserving order: iterate over order, derive
the full label or mapped category from the MemberGroup variant instead of using
split_whitespace().last(), track seen categories with a HashSet (or Vec +
contains) to avoid duplicates, push the full category strings into seen, and
then join seen into order_description so the resulting message uses clear,
complete group names.
- Around line 455-467: The current logic uses group.rank(order) and treats the
sentinel value order.len() like a normal rank, which causes unlisted groups to
inflate max_rank and wrongly trigger MemberOrderViolation; change the comparison
in the member-order loop so that when group.rank(order) == order.len() you skip
that member (do not compare against or assign to max_rank and do not push a
violation for it), leaving max_rank unchanged for subsequent listed groups;
reference the symbols max_rank, group.rank(order), MemberOrderViolation,
member_range and expected_before_name when locating and updating the code.
🧹 Nitpick comments (2)
crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs (2)

117-244: Consider extracting shared classification logic to reduce repetition.

The property, method, getter, and setter branches all follow the same pattern: extract is_static, is_hash_private, accessibility, then call resolve_*_group. A small generic helper could collapse these ~120 lines significantly. Not urgent, but would help maintainability as the rule evolves.


263-370: Could reduce boilerplate with a declarative macro.

The five has_static_modifier_* and four get_*_accessibility functions are structurally identical — only the types and variants differ. A small macro_rules! could generate them all. Purely optional, but would cut ~100 lines.

@thilllon
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs`:
- Around line 210-219: The TS getter/setter signature branches hardcode
is_hash_private=false; instead determine hash-private from the member name like
other cases: call is_hash_private_name on the signature's name (e.g. use
getter.name() / setter.name() to get the AnyJsClassMemberName and pass it to
is_hash_private_name) and pass that boolean into resolve_get_accessor_group /
resolve_set_accessor_group; keep existing is_static
(has_static_modifier_ts_method) and accessibility logic intact.
🧹 Nitpick comments (1)
crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs (1)

258-365: Consider a macro to reduce the modifier-helper boilerplate.

Five has_static_modifier_* and four get_*_accessibility functions are structurally identical, differing only in the modifier list type and variant path. A declarative macro could generate all of them from a table of (fn_name, list_type, variant_prefix) tuples, cutting ~110 lines down to ~20.

Not blocking — the current code is correct and the types unfortunately don't share a trait.

@thilllon
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 12, 2026

Merging this PR will degrade performance by 6.55%

❌ 1 regressed benchmark
✅ 57 untouched benchmarks
⏩ 95 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
js_analyzer[router_17129688031671448157.ts] 30 ms 32.1 ms -6.55%

Comparing thilllon:member-ordering (68059b6) with main (cf0db6c)

Open in CodSpeed

Footnotes

  1. 95 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

impl Rule for UseMemberOrdering {
type Query = Ast<JsClassMemberList>;
type State = MemberOrderViolation;
type Signals = Vec<Self::State>;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: boxed slice instead of Vec

Suggested change
type Signals = Vec<Self::State>;
type Signals = Box<[Self::State]>;

}
```

The default order is: index signatures, properties, accessors, constructors, methods, static blocks. The order is fully configurable via a `groups` option.
Copy link
Contributor

Choose a reason for hiding this comment

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

This option is undocumented in the rule.

Comment on lines 24 to 34
customOrder.options:2:5 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Found an unknown key `options`.

1 │ {
> 2 │ "options": {
│ ^^^^^^^^^
3 │ "groups": ["constructor", "method", "property"]
4 │ }

i Known keys:
Copy link
Contributor

Choose a reason for hiding this comment

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

this diagnostic shouldn't be here

class InvalidCustom {
name;
constructor() {}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

split this into 2, one valid and the other invalid. include the magic comments at the top to flag which one should or shouldn't emit diagnostics:

  • /* should not generate diagnostics */
  • /* should generate diagnostics */

if rank < max_r {
violations.push(MemberOrderViolation {
member_range: *range,
expected_before_name: max_label.to_string(),
Copy link
Contributor

Choose a reason for hiding this comment

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

avoid string allocation, use TokenText instead

};
let rank = group.rank(order);
// Skip members whose group is not listed in the configured order
if rank == sentinel {
Copy link
Contributor

Choose a reason for hiding this comment

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

this check doesn't look right to me. wouldn't it truncate instead of filter groups out? I could be misreading.

Comment on lines 104 to 105
.note(markup! {
"Members should be ordered by: "{order_description}"."
Copy link
Contributor

Choose a reason for hiding this comment

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

IIRC there's a footer_list helper that lets you avoid the string allocation here.

@github-actions github-actions bot added the A-Project Area: project label Feb 13, 2026
thilllon and others added 6 commits February 13, 2026 11:58
Add a new nursery lint rule `useMemberOrdering` that enforces a consistent
ordering of class members. This rule corresponds to ESLint TypeScript's
`@typescript-eslint/member-ordering`.

The default order is: index signatures, static properties, instance properties,
static accessors, instance accessors, static methods, constructor, instance
methods, static blocks. The order is fully configurable via a `groups` option.

Co-authored-by: Cursor <[email protected]>
- Change RuleSource from .same() to .inspired() since this implementation
  covers only class members, not interfaces/type literals/enums.
- Generate diagnostic note dynamically from the active ordering config
  instead of using a hardcoded message.
- Fix bug in find_order_violations: track maximum rank seen so far instead
  of previous member's rank, so violations after a lower-ranked member
  are not masked.

Co-authored-by: Cursor <[email protected]>
- Add broad_category() method to MemberGroup for clear diagnostic messages
  (e.g., "index signatures", "properties", "accessors", "constructors",
  "methods", "static blocks") instead of truncated last-word heuristic.
- Skip unlisted groups in find_order_violations to prevent sentinel rank
  values from inflating max_rank and causing false violations in custom
  configurations.

Co-authored-by: Cursor <[email protected]>
Replace hardcoded `false` for is_hash_private on TsGetterSignatureClassMember
and TsSetterSignatureClassMember with proper name checking via
is_hash_private_name(), consistent with all other member type branches.

Co-authored-by: Cursor <[email protected]>
- Use Box<[Self::State]> instead of Vec for type Signals
- Change expected_before_name from String to &'static str to avoid allocation
- Use footer_list helper in diagnostic instead of string join
- Add clarifying comment for sentinel check logic
- Split customOrder test into separate valid/invalid files with magic comments
- Document groups option in rule docstring and changeset
- Fix clippy warnings (explicit_into_iter_loop, map_unwrap_or)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs`:
- Around line 152-210: classify_member() currently only returns GetAccessor and
SetAccessor but the MemberGroup enum and default_order() include combined
variants like Accessor/StaticAccessor/ProtectedAccessor that will never be
produced; either remove those combined Accessor variants and their ranks from
MemberGroup and default_order() or, if they are reserved for TC39 auto-accessor
support, add a clear comment on the enum and in default_order() explaining they
are placeholders for the proposal and why classify_member() doesn't produce
them; update any code that matches on these combined variants (e.g.,
default_order(), ranking logic) to reflect the removal or to document planned
future support so custom orders like ["property","accessor","method"] behave as
expected.
- Around line 58-88: The rustdoc lists member group names in camelCase (e.g.,
indexSignature, hashPrivateProperty, staticBlock) but the actual deserialised
names are defined by the MemberGroup enum via #[serde(rename = "...")] and the
Deserializable macro (which expects kebab-case and `#private-`… forms); update the
documentation comment above use_member_ordering.rs to list the exact JSON keys
that the enum accepts (the serde-renamed variants such as index-signature,
static-index-signature, property, static-property, `#private-property` or
`#private-`… notation used in the enum, constructor, static-block, etc.) so copied
examples match the MemberGroup enum/Deserializable expectations (refer to
MemberGroup enum and the Deserializable macro for the canonical names to
document).
🧹 Nitpick comments (2)
crates/biome_rule_options/src/use_member_ordering.rs (1)

136-192: Consider making default_order a const or LazyLock<Vec<…>>.

default_order() allocates a fresh Vec of ~43 elements on every call. It's invoked in both run() and diagnostic() (the latter once per violation). For a class with many members, this could mean several allocations of the same data.

A const array or a static LazyLock would avoid the repeated heap allocation.

♻️ Sketch using a const array
-    pub fn default_order() -> Vec<MemberGroup> {
-        vec![
+    pub const DEFAULT_ORDER: &'static [MemberGroup] = &[
             // Index signatures
             MemberGroup::IndexSignature,
             MemberGroup::StaticIndexSignature,
             // ...same entries...
             MemberGroup::StaticBlock,
-        ]
-    }
+    ];
+
+    pub fn default_order() -> Vec<MemberGroup> {
+        Self::DEFAULT_ORDER.to_vec()
+    }

Then the callers that only need &[MemberGroup] can reference the const directly.

crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs (1)

126-149: Diagnostic recomputes groups() and deduplication for every violation.

options.groups() clones the full Vec<MemberGroup> and the broad-category dedup loop runs on each diagnostic() invocation. For a class with many out-of-order members, this is repeated work. Consider caching the order description string in MemberOrderViolation or computing it once via a shared approach.

Comment on lines +58 to +88
/// Available member groups:
/// - `indexSignature`, `staticIndexSignature`
/// - `property`, `staticProperty`, `protectedProperty`, `protectedStaticProperty`,
/// `privateProperty`, `privateStaticProperty`, `hashPrivateProperty`, `hashPrivateStaticProperty`
/// - `accessor`, `staticAccessor`, `protectedAccessor`, `protectedStaticAccessor`,
/// `privateAccessor`, `privateStaticAccessor`, `hashPrivateAccessor`, `hashPrivateStaticAccessor`
/// - `getAccessor`, `staticGetAccessor`, `protectedGetAccessor`, `protectedStaticGetAccessor`,
/// `privateGetAccessor`, `privateStaticGetAccessor`, `hashPrivateGetAccessor`, `hashPrivateStaticGetAccessor`
/// - `setAccessor`, `staticSetAccessor`, `protectedSetAccessor`, `protectedStaticSetAccessor`,
/// `privateSetAccessor`, `privateStaticSetAccessor`, `hashPrivateSetAccessor`, `hashPrivateStaticSetAccessor`
/// - `method`, `staticMethod`, `protectedMethod`, `protectedStaticMethod`,
/// `privateMethod`, `privateStaticMethod`, `hashPrivateMethod`, `hashPrivateStaticMethod`
/// - `constructor`
/// - `staticBlock`
///
/// Example custom order:
/// ```json
/// {
/// "linter": {
/// "rules": {
/// "nursery": {
/// "useMemberOrdering": {
/// "options": {
/// "groups": ["constructor", "method", "property"]
/// }
/// }
/// }
/// }
/// }
/// }
/// ```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find and examine the MemberGroup enum definition
rg -n "enum MemberGroup" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs -A 50

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check the exact serde rename attributes used
rg -n "serde.*rename" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs -B 1 -A 1 | head -100

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Search for test files or snapshots for useMemberOrdering rule
fd -i "usememberordering" crates/biome_js_analyze/tests/ --type f

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check if there are any JSON config examples in tests
find crates/biome_js_analyze/tests -name "*.json" | xargs grep -l "useMemberOrdering" 2>/dev/null | head -5

Repository: biomejs/biome

Length of output: 244


🏁 Script executed:

# Examine the Deserializable macro to understand its behaviour with serde rename
rg -n "impl.*Deserializable" crates/biome_deserialize/src/lib.rs -A 20 | head -80

Repository: biomejs/biome

Length of output: 2777


🏁 Script executed:

# Let's read the test JSON files to see the actual format used
cat crates/biome_js_analyze/tests/specs/nursery/useMemberOrdering/invalid_customOrder.options.json

Repository: biomejs/biome

Length of output: 332


🏁 Script executed:

cat crates/biome_js_analyze/tests/specs/nursery/useMemberOrdering/valid_customOrder.options.json

Repository: biomejs/biome

Length of output: 332


🏁 Script executed:

# Now find and examine the MemberGroup enum definition more carefully
cat crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs | head -150

Repository: biomejs/biome

Length of output: 5169


🏁 Script executed:

# Search more broadly for MemberGroup enum
rg -A 80 "^enum MemberGroup" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check the biome_deserialize_macros to understand how Deserializable handles serde(rename)
rg "serde.*rename" crates/biome_deserialize_macros/src/ -A 2 -B 2 | head -100

Repository: biomejs/biome

Length of output: 2475


🏁 Script executed:

# Find where MemberGroup is defined - it's likely in biome_rule_options
fd "use_member_ordering" crates/biome_rule_options/src/ --type f

Repository: biomejs/biome

Length of output: 109


🏁 Script executed:

# Read the rule options file containing MemberGroup
find crates/biome_rule_options -name "*use_member_ordering*" -type f -exec cat {} \;

Repository: biomejs/biome

Length of output: 12863


🏁 Script executed:

# Also check if there are more comprehensive test JSON files
find crates/biome_js_analyze/tests/specs/nursery/useMemberOrdering -type f -exec cat {} \;

Repository: biomejs/biome

Length of output: 17248


Correct the rustdoc group names to match the accepted JSON format.

The documentation lists available member groups in camelCase (e.g., indexSignature, hashPrivateProperty, staticBlock), but the MemberGroup enum variants are renamed via #[serde(rename)] to use kebab-case and #private-… notation, which the Deserializable macro honours. Users copying these names directly from the docs into their biome.json will encounter deserialisation errors.

Correction required for lines 59–71
 /// Available member groups:
-/// - `indexSignature`, `staticIndexSignature`
-/// - `property`, `staticProperty`, `protectedProperty`, `protectedStaticProperty`,
-///   `privateProperty`, `privateStaticProperty`, `hashPrivateProperty`, `hashPrivateStaticProperty`
-/// - `accessor`, `staticAccessor`, `protectedAccessor`, `protectedStaticAccessor`,
-///   `privateAccessor`, `privateStaticAccessor`, `hashPrivateAccessor`, `hashPrivateStaticAccessor`
-/// - `getAccessor`, `staticGetAccessor`, `protectedGetAccessor`, `protectedStaticGetAccessor`,
-///   `privateGetAccessor`, `privateStaticGetAccessor`, `hashPrivateGetAccessor`, `hashPrivateStaticGetAccessor`
-/// - `setAccessor`, `staticSetAccessor`, `protectedSetAccessor`, `protectedStaticSetAccessor`,
-///   `privateSetAccessor`, `privateStaticSetAccessor`, `hashPrivateSetAccessor`, `hashPrivateStaticSetAccessor`
-/// - `method`, `staticMethod`, `protectedMethod`, `protectedStaticMethod`,
-///   `privateMethod`, `privateStaticMethod`, `hashPrivateMethod`, `hashPrivateStaticMethod`
+/// - `index-signature`, `static-index-signature`
+/// - `property`, `static-property`, `protected-property`, `protected-static-property`,
+///   `private-property`, `private-static-property`, `#private-property`, `#private-static-property`
+/// - `accessor`, `static-accessor`, `protected-accessor`, `protected-static-accessor`,
+///   `private-accessor`, `private-static-accessor`, `#private-accessor`, `#private-static-accessor`
+/// - `get-accessor`, `static-get-accessor`, `protected-get-accessor`, `protected-static-get-accessor`,
+///   `private-get-accessor`, `private-static-get-accessor`, `#private-get-accessor`, `#private-static-get-accessor`
+/// - `set-accessor`, `static-set-accessor`, `protected-set-accessor`, `protected-static-set-accessor`,
+///   `private-set-accessor`, `private-static-set-accessor`, `#private-set-accessor`, `#private-static-set-accessor`
+/// - `method`, `static-method`, `protected-method`, `protected-static-method`,
+///   `private-method`, `private-static-method`, `#private-method`, `#private-static-method`
🤖 Prompt for AI Agents
In `@crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs` around lines
58 - 88, The rustdoc lists member group names in camelCase (e.g.,
indexSignature, hashPrivateProperty, staticBlock) but the actual deserialised
names are defined by the MemberGroup enum via #[serde(rename = "...")] and the
Deserializable macro (which expects kebab-case and `#private-`… forms); update the
documentation comment above use_member_ordering.rs to list the exact JSON keys
that the enum accepts (the serde-renamed variants such as index-signature,
static-index-signature, property, static-property, `#private-property` or
`#private-`… notation used in the enum, constructor, static-block, etc.) so copied
examples match the MemberGroup enum/Deserializable expectations (refer to
MemberGroup enum and the Deserializable macro for the canonical names to
document).

Copy link
Contributor

Choose a reason for hiding this comment

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

this is applicable

Comment on lines +152 to +210
/// Classify a class member into its `MemberGroup`.
fn classify_member(member: &AnyJsClassMember) -> Option<MemberGroup> {
match member {
AnyJsClassMember::JsConstructorClassMember(_) => Some(MemberGroup::Constructor),
AnyJsClassMember::JsPropertyClassMember(prop) => {
let is_static = has_static_modifier_property(&prop.modifiers());
let is_hash_private = prop
.name()
.ok()
.is_some_and(|n| is_hash_private_name(&n));
let accessibility = get_property_accessibility(&prop.modifiers());
Some(resolve_property_group(
is_static,
&accessibility,
is_hash_private,
))
}
AnyJsClassMember::JsMethodClassMember(method) => {
let is_static = has_static_modifier_method(&method.modifiers());
let is_hash_private = method
.name()
.ok()
.is_some_and(|n| is_hash_private_name(&n));
let accessibility = get_method_accessibility(&method.modifiers());
Some(resolve_method_group(
is_static,
&accessibility,
is_hash_private,
))
}
AnyJsClassMember::JsGetterClassMember(getter) => {
let is_static = has_static_modifier_method(&getter.modifiers());
let is_hash_private = getter
.name()
.ok()
.is_some_and(|n| is_hash_private_name(&n));
let accessibility = get_method_accessibility(&getter.modifiers());
Some(resolve_get_accessor_group(
is_static,
&accessibility,
is_hash_private,
))
}
AnyJsClassMember::JsSetterClassMember(setter) => {
let is_static = has_static_modifier_method(&setter.modifiers());
let is_hash_private = setter
.name()
.ok()
.is_some_and(|n| is_hash_private_name(&n));
let accessibility = get_method_accessibility(&setter.modifiers());
Some(resolve_set_accessor_group(
is_static,
&accessibility,
is_hash_private,
))
}
AnyJsClassMember::JsStaticInitializationBlockClassMember(_) => {
Some(MemberGroup::StaticBlock)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find the MemberGroup enum definition
rg -A 30 "enum MemberGroup" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs | head -50

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check the AnyJsClassMember definition in biome_js_syntax
fd "nodes.rs" crates/biome_js_syntax/src/generated/ | head -1 | xargs rg -A 50 "enum AnyJsClassMember" | head -70

Repository: biomejs/biome

Length of output: 2748


🏁 Script executed:

# Look for the default_order function to see what MemberGroup variants are listed
rg -B 5 -A 50 "fn default_order" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Find MemberGroup enum definition more directly
rg "enum MemberGroup" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs -A 50

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Find the default_order function
rg "default_order\|fn.*default" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs -B 2 -A 30

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check if there are any mentions of "Accessor" in MemberGroup or default_order context
rg "Accessor" crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs | head -20

Repository: biomejs/biome

Length of output: 1765


🏁 Script executed:

# Read the file to find MemberGroup enum definition
cat -n crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs | grep -A 100 "^[[:space:]]*[0-9]*[[:space:]]*enum MemberGroup" | head -120

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Also check the file structure - get line count and see the enum at beginning
wc -l crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs

Repository: biomejs/biome

Length of output: 124


🏁 Script executed:

# Read from the start of the file to find MemberGroup
head -200 crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs | tail -150

Repository: biomejs/biome

Length of output: 5869


🏁 Script executed:

# Read the beginning of the file to find MemberGroup enum
head -100 crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs

Repository: biomejs/biome

Length of output: 3569


🏁 Script executed:

# Find the MemberGroup enum definition in biome_rule_options
find . -name "*.rs" -path "*/biome_rule_options/*" | xargs grep -l "enum MemberGroup" | head -5

Repository: biomejs/biome

Length of output: 111


🏁 Script executed:

# Broader search for MemberGroup enum definition
fd "use_member_ordering" --type f | xargs grep -l "enum MemberGroup"

Repository: biomejs/biome

Length of output: 109


🏁 Script executed:

# Read the MemberGroup enum definition file
cat -n crates/biome_rule_options/src/use_member_ordering.rs

Repository: biomejs/biome

Length of output: 14949


Combined Accessor groups are dead entries — they'll never match getters or setters.

classify_member() produces only GetAccessor and SetAccessor variants. The combined Accessor, StaticAccessor, ProtectedAccessor, etc. live in the enum and default_order() but no code path ever creates them. This means:

  • In the default order: inert rank slots (noise, no functional bug).
  • In a custom order like ["property", "accessor", "method"]: users would expect getters and setters to match "accessor", but they won't—they'll silently fall through to the sentinel rank.

If these are placeholders for the TC39 auto-accessor proposal (accessor name;), add a comment explaining that. If not, remove them and their ranks from default_order().

🤖 Prompt for AI Agents
In `@crates/biome_js_analyze/src/lint/nursery/use_member_ordering.rs` around lines
152 - 210, classify_member() currently only returns GetAccessor and SetAccessor
but the MemberGroup enum and default_order() include combined variants like
Accessor/StaticAccessor/ProtectedAccessor that will never be produced; either
remove those combined Accessor variants and their ranks from MemberGroup and
default_order() or, if they are reserved for TC39 auto-accessor support, add a
clear comment on the enum and in default_order() explaining they are
placeholders for the proposal and why classify_member() doesn't produce them;
update any code that matches on these combined variants (e.g., default_order(),
ranking logic) to reflect the removal or to document planned future support so
custom orders like ["property","accessor","method"] behave as expected.

Copy link
Contributor

Choose a reason for hiding this comment

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

this might also be applicable

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

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants