1
1
/*
2
- * Copyright 2016-2021 DiffPlug
2
+ * Copyright 2016-2022 DiffPlug
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
17
17
18
18
import java .io .Serializable ;
19
19
import java .util .*;
20
+ import java .util .stream .Collectors ;
21
+ import java .util .stream .Stream ;
20
22
21
23
import javax .annotation .Nullable ;
22
24
25
27
// which itself is licensed under the Apache 2.0 license.
26
28
final class ImportSorterImpl {
27
29
28
- private final List <String > template = new ArrayList <>();
30
+ private static final String CATCH_ALL_SUBGROUP = "" ;
31
+ private static final String STATIC_KEYWORD = "static " ;
32
+ private static final String STATIC_SYMBOL = "\\ #" ;
33
+ private static final String SUBGROUP_SEPARATOR = "|" ;
34
+
35
+ private final List <ImportsGroup > importsGroups ;
29
36
private final Map <String , List <String >> matchingImports = new HashMap <>();
30
37
private final List <String > notMatching = new ArrayList <>();
31
38
private final Set <String > allImportOrderItems = new HashSet <>();
32
39
private final Comparator <String > ordering ;
33
40
41
+ // An ImportsGroup is a group of imports ; each group is separated by blank lines.
42
+ // A group is composed of subgroups : imports are sorted by subgroup.
43
+ private static class ImportsGroup {
44
+
45
+ private final List <String > subGroups ;
46
+
47
+ public ImportsGroup (String importOrder ) {
48
+ this .subGroups = Stream .of (importOrder .split ("\\ " + SUBGROUP_SEPARATOR ))
49
+ .map (this ::normalizeStatic )
50
+ .collect (Collectors .toList ());
51
+ }
52
+
53
+ private String normalizeStatic (String subgroup ) {
54
+ if (subgroup .startsWith (STATIC_SYMBOL )) {
55
+ return subgroup .replace (STATIC_SYMBOL , STATIC_KEYWORD );
56
+ }
57
+ return subgroup ;
58
+ }
59
+
60
+ public List <String > getSubGroups () {
61
+ return subGroups ;
62
+ }
63
+ }
64
+
34
65
static List <String > sort (List <String > imports , List <String > importsOrder , boolean wildcardsLast , String lineFormat ) {
35
66
ImportSorterImpl importsSorter = new ImportSorterImpl (importsOrder , wildcardsLast );
36
67
return importsSorter .sort (imports , lineFormat );
@@ -40,43 +71,42 @@ private List<String> sort(List<String> imports, String lineFormat) {
40
71
filterMatchingImports (imports );
41
72
mergeNotMatchingItems (false );
42
73
mergeNotMatchingItems (true );
43
- mergeMatchingItems ();
74
+ List < String > sortedImported = mergeMatchingItems ();
44
75
45
- return getResult (lineFormat );
76
+ return getResult (sortedImported , lineFormat );
46
77
}
47
78
48
79
private ImportSorterImpl (List <String > importOrder , boolean wildcardsLast ) {
49
- List < String > importOrderCopy = new ArrayList <>( importOrder );
50
- normalizeStaticOrderItems ( importOrderCopy );
51
- putStaticItemIfNotExists ( importOrderCopy );
52
- template . addAll ( importOrderCopy );
80
+ importsGroups = importOrder . stream (). filter ( Objects :: nonNull ). map ( ImportsGroup :: new ). collect ( Collectors . toList () );
81
+ putStaticItemIfNotExists ( importsGroups );
82
+ putCatchAllGroupIfNotExists ( importsGroups );
83
+
53
84
ordering = new OrderingComparator (wildcardsLast );
54
- this .allImportOrderItems .addAll (importOrderCopy );
85
+
86
+ List <String > subgroups = importsGroups .stream ().map (ImportsGroup ::getSubGroups ).flatMap (Collection ::stream ).collect (Collectors .toList ());
87
+ this .allImportOrderItems .addAll (subgroups );
55
88
}
56
89
57
- private static void putStaticItemIfNotExists (List <String > allImportOrderItems ) {
58
- boolean contains = false ;
90
+ private void putStaticItemIfNotExists (List <ImportsGroup > importsGroups ) {
91
+ boolean catchAllSubGroupExist = importsGroups .stream ().anyMatch (group -> group .getSubGroups ().contains (STATIC_KEYWORD ));
92
+ if (catchAllSubGroupExist ) {
93
+ return ;
94
+ }
95
+
59
96
int indexOfFirstStatic = 0 ;
60
- for (int i = 0 ; i < allImportOrderItems .size (); i ++) {
61
- String allImportOrderItem = allImportOrderItems .get (i );
62
- if (allImportOrderItem .equals ("static " )) {
63
- contains = true ;
64
- }
65
- if (allImportOrderItem .startsWith ("static " )) {
97
+ for (int i = 0 ; i < importsGroups .size (); i ++) {
98
+ boolean subgroupMatch = importsGroups .get (i ).getSubGroups ().stream ().anyMatch (subgroup -> subgroup .startsWith (STATIC_KEYWORD ));
99
+ if (subgroupMatch ) {
66
100
indexOfFirstStatic = i ;
67
101
}
68
102
}
69
- if (!contains ) {
70
- allImportOrderItems .add (indexOfFirstStatic , "static " );
71
- }
103
+ importsGroups .add (indexOfFirstStatic , new ImportsGroup (STATIC_KEYWORD ));
72
104
}
73
105
74
- private static void normalizeStaticOrderItems (List <String > allImportOrderItems ) {
75
- for (int i = 0 ; i < allImportOrderItems .size (); i ++) {
76
- String s = allImportOrderItems .get (i );
77
- if (s .startsWith ("\\ #" )) {
78
- allImportOrderItems .set (i , s .replace ("\\ #" , "static " ));
79
- }
106
+ private void putCatchAllGroupIfNotExists (List <ImportsGroup > importsGroups ) {
107
+ boolean catchAllSubGroupExist = importsGroups .stream ().anyMatch (group -> group .getSubGroups ().contains (CATCH_ALL_SUBGROUP ));
108
+ if (!catchAllSubGroupExist ) {
109
+ importsGroups .add (new ImportsGroup (CATCH_ALL_SUBGROUP ));
80
110
}
81
111
}
82
112
@@ -87,9 +117,7 @@ private void filterMatchingImports(List<String> imports) {
87
117
for (String anImport : imports ) {
88
118
String orderItem = getBestMatchingImportOrderItem (anImport );
89
119
if (orderItem != null ) {
90
- if (!matchingImports .containsKey (orderItem )) {
91
- matchingImports .put (orderItem , new ArrayList <>());
92
- }
120
+ matchingImports .computeIfAbsent (orderItem , key -> new ArrayList <>());
93
121
matchingImports .get (orderItem ).add (anImport );
94
122
} else {
95
123
notMatching .add (anImport );
@@ -116,34 +144,14 @@ private void filterMatchingImports(List<String> imports) {
116
144
* not matching means it does not match any order item, so it will be appended before or after order items
117
145
*/
118
146
private void mergeNotMatchingItems (boolean staticItems ) {
119
- sort (notMatching );
120
-
121
- int firstIndexOfOrderItem = getFirstIndexOfOrderItem (notMatching , staticItems );
122
- int indexOfOrderItem = 0 ;
123
147
for (String notMatchingItem : notMatching ) {
124
148
if (!matchesStatic (staticItems , notMatchingItem )) {
125
149
continue ;
126
150
}
127
151
boolean isOrderItem = isOrderItem (notMatchingItem , staticItems );
128
- if (isOrderItem ) {
129
- indexOfOrderItem = template .indexOf (notMatchingItem );
130
- } else {
131
- if (indexOfOrderItem == 0 && firstIndexOfOrderItem != 0 ) {
132
- // insert before alphabetically first order item
133
- template .add (firstIndexOfOrderItem , notMatchingItem );
134
- firstIndexOfOrderItem ++;
135
- } else if (firstIndexOfOrderItem == 0 ) {
136
- // no order is specified
137
- if (template .size () > 0 && (template .get (template .size () - 1 ).startsWith ("static" ))) {
138
- // insert N after last static import
139
- template .add (ImportSorter .N );
140
- }
141
- template .add (notMatchingItem );
142
- } else {
143
- // insert after the previous order item
144
- template .add (indexOfOrderItem + 1 , notMatchingItem );
145
- indexOfOrderItem ++;
146
- }
152
+ if (!isOrderItem ) {
153
+ matchingImports .computeIfAbsent (CATCH_ALL_SUBGROUP , key -> new ArrayList <>());
154
+ matchingImports .get (CATCH_ALL_SUBGROUP ).add (notMatchingItem );
147
155
}
148
156
}
149
157
}
@@ -153,76 +161,44 @@ private boolean isOrderItem(String notMatchingItem, boolean staticItems) {
153
161
return contains && matchesStatic (staticItems , notMatchingItem );
154
162
}
155
163
156
- /**
157
- * gets first order item from sorted input list, and finds out it's index in template.
158
- */
159
- private int getFirstIndexOfOrderItem (List <String > notMatching , boolean staticItems ) {
160
- int firstIndexOfOrderItem = 0 ;
161
- for (String notMatchingItem : notMatching ) {
162
- if (!matchesStatic (staticItems , notMatchingItem )) {
163
- continue ;
164
- }
165
- boolean isOrderItem = isOrderItem (notMatchingItem , staticItems );
166
- if (isOrderItem ) {
167
- firstIndexOfOrderItem = template .indexOf (notMatchingItem );
168
- break ;
169
- }
170
- }
171
- return firstIndexOfOrderItem ;
172
- }
173
-
174
164
private static boolean matchesStatic (boolean staticItems , String notMatchingItem ) {
175
- boolean isStatic = notMatchingItem .startsWith ("static " );
165
+ boolean isStatic = notMatchingItem .startsWith (STATIC_KEYWORD );
176
166
return (isStatic && staticItems ) || (!isStatic && !staticItems );
177
167
}
178
168
179
- private void mergeMatchingItems () {
180
- for ( int i = 0 ; i < template . size (); i ++) {
181
- String item = template . get ( i );
182
- if ( allImportOrderItems . contains ( item )) {
183
- // find matching items for order item
184
- List <String > strings = matchingImports .get (item );
169
+ private List < String > mergeMatchingItems () {
170
+ List < String > template = new ArrayList <> ();
171
+ for ( ImportsGroup group : importsGroups ) {
172
+ boolean groupIsNotEmpty = false ;
173
+ for ( String subgroup : group . getSubGroups ()) {
174
+ List <String > strings = matchingImports .get (subgroup );
185
175
if (strings == null || strings .isEmpty ()) {
186
- // if there is none, just remove order item
187
- template .remove (i );
188
- i --;
189
176
continue ;
190
177
}
178
+ groupIsNotEmpty = true ;
191
179
List <String > matchingItems = new ArrayList <>(strings );
192
180
sort (matchingItems );
193
-
194
- // replace order item by matching import statements
195
- // this is a mess and it is only a luck that it works :-]
196
- template .remove (i );
197
- if (i != 0 && !template .get (i - 1 ).equals (ImportSorter .N )) {
198
- template .add (i , ImportSorter .N );
199
- i ++;
200
- }
201
- if (i + 1 < template .size () && !template .get (i + 1 ).equals (ImportSorter .N )
202
- && !template .get (i ).equals (ImportSorter .N )) {
203
- template .add (i , ImportSorter .N );
204
- }
205
- template .addAll (i , matchingItems );
206
- if (i != 0 && !template .get (i - 1 ).equals (ImportSorter .N )) {
207
- template .add (i , ImportSorter .N );
208
- }
209
-
181
+ template .addAll (matchingItems );
182
+ }
183
+ if (groupIsNotEmpty ) {
184
+ template .add (ImportSorter .N );
210
185
}
211
186
}
212
187
// if there is \n on the end, remove it
213
- if (template .size () > 0 && template .get (template .size () - 1 ).equals (ImportSorter .N )) {
188
+ if (! template .isEmpty () && template .get (template .size () - 1 ).equals (ImportSorter .N )) {
214
189
template .remove (template .size () - 1 );
215
190
}
191
+ return template ;
216
192
}
217
193
218
194
private void sort (List <String > items ) {
219
195
items .sort (ordering );
220
196
}
221
197
222
- private List <String > getResult (String lineFormat ) {
198
+ private List <String > getResult (List < String > sortedImported , String lineFormat ) {
223
199
List <String > strings = new ArrayList <>();
224
200
225
- for (String s : template ) {
201
+ for (String s : sortedImported ) {
226
202
if (s .equals (ImportSorter .N )) {
227
203
strings .add (s );
228
204
} else {
0 commit comments