Skip to content

Commit

Permalink
Java importOrder support for sorting wildcards last
Browse files Browse the repository at this point in the history
Adds support for sorting wildcards after non-wildcards in the import list. Gradle config like so:

```
importOrder('java', 'javax', 'com.acme', '').wildcardsLast()
```

Not implemented here: Maven plugin support

Fixes diffplug#879.
  • Loading branch information
hakanai committed Oct 1, 2021
1 parent ae5529e commit 3b74071
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 27 deletions.
24 changes: 17 additions & 7 deletions lib/src/main/java/com/diffplug/spotless/java/ImportOrderStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,28 @@ private ImportOrderStep(String lineFormat) {
}

public FormatterStep createFrom(String... importOrder) {
return createFrom(false, importOrder);
}

public FormatterStep createFrom(boolean wildcardsLast, String... importOrder) {
// defensive copying and null checking
List<String> importOrderList = requireElementsNonNull(Arrays.asList(importOrder));
return createFrom(() -> importOrderList);
return createFrom(wildcardsLast, () -> importOrderList);
}

public FormatterStep createFrom(File importsFile) {
return createFrom(false, importsFile);
}

public FormatterStep createFrom(boolean wildcardsLast, File importsFile) {
Objects.requireNonNull(importsFile);
return createFrom(() -> getImportOrder(importsFile));
return createFrom(wildcardsLast, () -> getImportOrder(importsFile));
}

private FormatterStep createFrom(Supplier<List<String>> importOrder) {
private FormatterStep createFrom(boolean wildcardsLast, Supplier<List<String>> importOrder) {
return FormatterStep.createLazy("importOrder",
() -> new State(importOrder.get(), lineFormat),
State::toFormatter);
() -> new State(importOrder.get(), lineFormat, wildcardsLast),
State::toFormatter);
}

private static List<String> getImportOrder(File importsFile) {
Expand Down Expand Up @@ -92,14 +100,16 @@ private static final class State implements Serializable {

private final List<String> importOrder;
private final String lineFormat;
private final boolean wildcardsLast;

State(List<String> importOrder, String lineFormat) {
State(List<String> importOrder, String lineFormat, boolean wildcardsLast) {
this.importOrder = importOrder;
this.lineFormat = lineFormat;
this.wildcardsLast = wildcardsLast;
}

FormatterFunc toFormatter() {
return raw -> new ImportSorter(importOrder).format(raw, lineFormat);
return raw -> new ImportSorter(importOrder, wildcardsLast).format(raw, lineFormat);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ final class ImportSorter {
static final String N = "\n";

private final List<String> importsOrder;
private final boolean wildcardsLast;

ImportSorter(List<String> importsOrder) {
ImportSorter(List<String> importsOrder, boolean wildcardsLast) {
this.importsOrder = new ArrayList<>(importsOrder);
this.wildcardsLast = wildcardsLast;
}

String format(String raw, String lineFormat) {
Expand Down Expand Up @@ -79,7 +81,7 @@ String format(String raw, String lineFormat) {
}
scanner.close();

List<String> sortedImports = ImportSorterImpl.sort(imports, importsOrder, lineFormat);
List<String> sortedImports = ImportSorterImpl.sort(imports, importsOrder, wildcardsLast, lineFormat);
return applyImportsToDocument(raw, firstImportLine, lastImportLine, sortedImports);
}

Expand Down
48 changes: 36 additions & 12 deletions lib/src/main/java/com/diffplug/spotless/java/ImportSorterImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@
*/
package com.diffplug.spotless.java;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;

import javax.annotation.Nullable;

Expand All @@ -34,9 +28,10 @@ final class ImportSorterImpl {
private final Map<String, List<String>> matchingImports = new HashMap<>();
private final List<String> notMatching = new ArrayList<>();
private final Set<String> allImportOrderItems = new HashSet<>();
private final Comparator<String> ordering;

static List<String> sort(List<String> imports, List<String> importsOrder, String lineFormat) {
ImportSorterImpl importsSorter = new ImportSorterImpl(importsOrder);
static List<String> sort(List<String> imports, List<String> importsOrder, boolean wildcardsLast, String lineFormat) {
ImportSorterImpl importsSorter = new ImportSorterImpl(importsOrder, wildcardsLast);
return importsSorter.sort(imports, lineFormat);
}

Expand All @@ -49,11 +44,12 @@ private List<String> sort(List<String> imports, String lineFormat) {
return getResult(lineFormat);
}

private ImportSorterImpl(List<String> importOrder) {
private ImportSorterImpl(List<String> importOrder, boolean wildcardsLast) {
List<String> importOrderCopy = new ArrayList<>(importOrder);
normalizeStaticOrderItems(importOrderCopy);
putStaticItemIfNotExists(importOrderCopy);
template.addAll(importOrderCopy);
ordering = new OrderingComparator(wildcardsLast);
this.allImportOrderItems.addAll(importOrderCopy);
}

Expand Down Expand Up @@ -119,7 +115,7 @@ private void filterMatchingImports(List<String> imports) {
* not matching means it does not match any order item, so it will be appended before or after order items
*/
private void mergeNotMatchingItems(boolean staticItems) {
Collections.sort(notMatching);
sort(notMatching);

int firstIndexOfOrderItem = getFirstIndexOfOrderItem(notMatching, staticItems);
int indexOfOrderItem = 0;
Expand Down Expand Up @@ -192,7 +188,7 @@ private void mergeMatchingItems() {
continue;
}
List<String> matchingItems = new ArrayList<>(strings);
Collections.sort(matchingItems);
sort(matchingItems);

// replace order item by matching import statements
// this is a mess and it is only a luck that it works :-]
Expand All @@ -218,6 +214,10 @@ private void mergeMatchingItems() {
}
}

private void sort(List<String> items) {
items.sort(ordering);
}

private List<String> getResult(String lineFormat) {
List<String> strings = new ArrayList<>();

Expand Down Expand Up @@ -256,4 +256,28 @@ private List<String> getResult(String lineFormat) {
return null;
}

private static class OrderingComparator implements Comparator<String> {
private final boolean wildcardsLast;

private OrderingComparator(boolean wildcardsLast) {
this.wildcardsLast = wildcardsLast;
}

@Override
public int compare(String string1, String string2) {
int string1WildcardIndex = string1.indexOf('*');
int string2WildcardIndex = string2.indexOf('*');
boolean string1IsWildcard = string1WildcardIndex >= 0;
boolean string2IsWildcard = string2WildcardIndex >= 0;
if (string1IsWildcard == string2IsWildcard) {
return string1.compareTo(string2);
}
int prefixLength = string1IsWildcard ? string1WildcardIndex : string2WildcardIndex;
boolean samePrefix = string1.regionMatches(0, string2, 0, prefixLength);
if (!samePrefix) {
return string1.compareTo(string2);
}
return (string1IsWildcard == wildcardsLast) ? 1 : -1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import static com.diffplug.gradle.spotless.PluginGradlePreconditions.requireElementsNonNull;

import java.io.File;
import java.util.Objects;

import javax.inject.Inject;
Expand Down Expand Up @@ -57,13 +58,47 @@ public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile) {
return licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
}

public void importOrder(String... importOrder) {
addStep(ImportOrderStep.forJava().createFrom(importOrder));
public ImportOrderConfig importOrder(String... importOrder) {
return new ImportOrderConfig(importOrder);
}

public void importOrderFile(Object importOrderFile) {
public ImportOrderConfig importOrderFile(Object importOrderFile) {
Objects.requireNonNull(importOrderFile);
addStep(ImportOrderStep.forJava().createFrom(getProject().file(importOrderFile)));
return new ImportOrderConfig(getProject().file(importOrderFile));
}

public class ImportOrderConfig {
final String[] importOrder;
final File importOrderFile;

boolean wildcardsLast = false;

ImportOrderConfig(String[] importOrder) {
this.importOrder = importOrder;
importOrderFile = null;
addStep(createStep());
}

ImportOrderConfig(File importOrderFile) {
importOrder = null;
this.importOrderFile = importOrderFile;
addStep(createStep());
}

/** Sorts wildcard imports after non-wildcard imports, instead of before. */
public ImportOrderConfig wildcardsLast() {
wildcardsLast = true;
replaceStep(createStep());
return this;
}

private FormatterStep createStep() {
ImportOrderStep importOrderStep = ImportOrderStep.forJava();

return importOrderFile != null
? importOrderStep.createFrom(wildcardsLast, getProject().file(importOrderFile))
: importOrderStep.createFrom(wildcardsLast, importOrder);
}
}

/** Removes any unused imports. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ import java.lang.Runnable;
import org.comments.be
import org.comments.removed
*/
import static java.lang.Runnable.*;
import static java.lang.Runnable.*;
/*
import other.multiline.comments
import will.be.removed.too */
import will.be.removed.too */
import static com.foo.Bar
import java.awt.*;
import java.util.*;
import java.util.List;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static org.hamcrest.Matchers.*;
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import java.awt.*;
import java.lang.Runnable;
import java.lang.Thread;
import java.util.*;
import java.util.List;

import org.dooda.Didoo;

import static java.lang.Exception.*;
import static java.lang.Runnable.*;
import static org.hamcrest.Matchers.*;

import static com.foo.Bar;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import static com.foo.Bar;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static java.lang.Exception.*;
import static java.lang.Runnable.*;
import static org.hamcrest.Matchers.*;

import java.awt.*;
import java.lang.Runnable;
import java.lang.Thread;
import java.util.*;
import java.util.List;
import org.dooda.Didoo;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import static com.foo.Bar;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static java.lang.Exception.*;
import static java.lang.Runnable.*;
import static org.hamcrest.Matchers.*;

import java.awt.*;
import java.lang.Runnable;
import java.lang.Thread;
import java.util.List;
import java.util.*;
import org.dooda.Didoo;
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import static java.lang.Exception.*;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import org.dooda.Didoo;
import java.util.List;
import java.lang.Thread;
import java.util.*;
import java.lang.Runnable;
import static org.hamcrest.Matchers.*;

import static java.lang.Runnable.*;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.foo.Bar
import java.awt.*;
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ void sortImportsUnmatched() throws Throwable {
assertOnResources(step, "java/importsorter/JavaCodeUnsortedImportsUnmatched.test", "java/importsorter/JavaCodeSortedImportsUnmatched.test");
}

@Test
void sortImportsWildcardsLast() throws Throwable {
FormatterStep step = ImportOrderStep.forJava().createFrom(true);
assertOnResources(step, "java/importsorter/JavaCodeUnsortedImports.test", "java/importsorter/JavaCodeSortedImportsWildcardsLast.test");
}

@Test
void removeDuplicates() throws Throwable {
FormatterStep step = ImportOrderStep.forJava().createFrom(createTestFile("java/importsorter/import_unmatched.properties"));
Expand Down

0 comments on commit 3b74071

Please sign in to comment.