@@ -88,54 +88,45 @@ impl Rule for UseSortedKeys {
8888 type Options = ( ) ;
8989
9090 fn run ( ctx : & RuleContext < Self > ) -> Self :: Signals {
91- let mut members = Vec :: new ( ) ;
92- let mut groups = Vec :: new ( ) ;
91+ let member_list = ctx. query ( ) ;
92+ let mut chunks = Vec :: new ( ) ;
93+ let mut current_chunk_members = Vec :: with_capacity ( member_list. len ( ) ) ;
9394
9495 let get_name = |name : SyntaxResult < AnyJsObjectMemberName > | name. ok ( ) ?. name ( ) ;
9596
96- for element in ctx. query ( ) . elements ( ) {
97- if let Ok ( element) = element. node ( ) {
98- match element {
99- AnyJsObjectMember :: JsSpread ( _) | AnyJsObjectMember :: JsBogusMember ( _) => {
100- // Keep the spread order because it's not safe to change order of it.
101- // Logic here is similar to /crates/biome_js_analyze/src/assists/source/use_sorted_attributes.rs
102- if !members. is_empty ( ) && !members. is_sorted ( ) {
103- groups. push ( members. clone ( ) ) ;
104- }
105- // Reuse the same buffer
106- members. clear ( ) ;
107- members. push ( ObjectMember :: new ( element. clone ( ) , None ) ) ;
108- }
109- AnyJsObjectMember :: JsPropertyObjectMember ( member) => {
110- members. push ( ObjectMember :: new ( element. clone ( ) , get_name ( member. name ( ) ) ) ) ;
111- }
112- AnyJsObjectMember :: JsGetterObjectMember ( member) => {
113- members. push ( ObjectMember :: new ( element. clone ( ) , get_name ( member. name ( ) ) ) ) ;
114- }
115- AnyJsObjectMember :: JsSetterObjectMember ( member) => {
116- members. push ( ObjectMember :: new ( element. clone ( ) , get_name ( member. name ( ) ) ) ) ;
117- }
118- AnyJsObjectMember :: JsMethodObjectMember ( member) => {
119- members. push ( ObjectMember :: new ( element. clone ( ) , get_name ( member. name ( ) ) ) ) ;
120- }
97+ for ( index, element) in member_list. elements ( ) . enumerate ( ) {
98+ if let Ok ( element) = element. into_node ( ) {
99+ let name = match & element {
100+ AnyJsObjectMember :: JsSpread ( _) | AnyJsObjectMember :: JsBogusMember ( _) => None ,
101+ AnyJsObjectMember :: JsPropertyObjectMember ( member) => get_name ( member. name ( ) ) ,
102+ AnyJsObjectMember :: JsGetterObjectMember ( member) => get_name ( member. name ( ) ) ,
103+ AnyJsObjectMember :: JsSetterObjectMember ( member) => get_name ( member. name ( ) ) ,
104+ AnyJsObjectMember :: JsMethodObjectMember ( member) => get_name ( member. name ( ) ) ,
121105 AnyJsObjectMember :: JsShorthandPropertyObjectMember ( member) => {
122- let name = member
123- . name ( )
124- . ok ( )
125- . map ( |name| name. name ( ) . ok ( ) )
126- . unwrap_or_default ( ) ;
127-
128- members. push ( ObjectMember :: new ( element. clone ( ) , name) ) ;
106+ member. name ( ) . and_then ( |name| name. name ( ) ) . ok ( )
107+ }
108+ } ;
109+ if let Some ( name) = name {
110+ current_chunk_members. push ( ObjectMember :: new ( element, name) ) ;
111+ } else {
112+ // If a name cannot be extracted, then the current chunk of named properties stops here.
113+ if !current_chunk_members. is_empty ( ) && !current_chunk_members. is_sorted ( ) {
114+ chunks. push ( current_chunk_members) ;
115+ // Create a new buffer with the number of remaining members to test
116+ current_chunk_members = Vec :: with_capacity ( member_list. len ( ) - index - 1 ) ;
117+ } else {
118+ // Reuse the buffer
119+ current_chunk_members. clear ( ) ;
129120 }
130121 }
131122 }
132123 }
133124
134- if !members . is_empty ( ) && !members . is_sorted ( ) {
135- groups . push ( members ) ;
125+ if !current_chunk_members . is_empty ( ) && !current_chunk_members . is_sorted ( ) {
126+ chunks . push ( current_chunk_members ) ;
136127 }
137128
138- groups . into_boxed_slice ( )
129+ chunks . into_boxed_slice ( )
139130 }
140131
141132 fn diagnostic ( ctx : & RuleContext < Self > , _state : & Self :: State ) -> Option < RuleDiagnostic > {
@@ -159,13 +150,9 @@ impl Rule for UseSortedKeys {
159150 fn action ( ctx : & RuleContext < Self > , state : & Self :: State ) -> Option < JsRuleAction > {
160151 let mut sorted_state = state. clone ( ) ;
161152
162- sorted_state. sort_unstable ( ) ;
163-
164- // FIXME: why do we need to check it?
165- // Checking if it is sorted in `run` should be enough.
166- if & sorted_state == state {
167- return None ;
168- }
153+ // We use a stable sort to ensure that properties with an identical name (a getter and a setter for a property)
154+ // keep their initial relative order.
155+ sorted_state. sort ( ) ;
169156
170157 let mut mutation = ctx. root ( ) . begin ( ) ;
171158
@@ -185,10 +172,10 @@ impl Rule for UseSortedKeys {
185172#[ derive( Debug , Clone ) ]
186173pub struct ObjectMember {
187174 member : AnyJsObjectMember ,
188- name : Option < TokenText > ,
175+ name : TokenText ,
189176}
190177impl ObjectMember {
191- fn new ( member : AnyJsObjectMember , name : Option < TokenText > ) -> Self {
178+ fn new ( member : AnyJsObjectMember , name : TokenText ) -> Self {
192179 Self { member, name }
193180 }
194181}
@@ -200,16 +187,14 @@ impl PartialEq for ObjectMember {
200187}
201188impl Ord for ObjectMember {
202189 fn cmp ( & self , other : & Self ) -> Ordering {
203- // If some doesn't have a name (e.g spread/calculated property) - keep the order.
204- let ( Some ( self_name) , Some ( other_name) ) = ( & self . name , & other. name ) else {
205- return Ordering :: Equal ;
206- } ;
207-
208- self_name. text ( ) . ascii_nat_cmp ( other_name. text ( ) )
190+ self . name . text ( ) . ascii_nat_cmp ( other. name . text ( ) )
209191 }
210192}
211193impl PartialOrd for ObjectMember {
212194 fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
213195 Some ( self . cmp ( other) )
214196 }
215197}
198+
199+ #[ test]
200+ fn test ( ) { }
0 commit comments