From d469a3548b6e85dda82d15e466d48f4e0c12fade Mon Sep 17 00:00:00 2001 From: samypr100 <3933065+samypr100@users.noreply.github.com> Date: Sat, 2 Sep 2023 23:19:04 -0400 Subject: [PATCH 1/5] feat: add support for prettier v3 plugin changes --- CHANGES.md | 3 + .../spotless/npm/PrettierRestService.java | 12 ++ plugin-gradle/CHANGES.md | 3 + plugin-gradle/README.md | 2 + .../spotless/PrettierIntegrationTest.java | 184 ++++++++++++++---- plugin-maven/CHANGES.md | 3 + plugin-maven/README.md | 2 + .../spotless/maven/generic/Prettier.java | 5 + .../prettier/PrettierFormatStepTest.java | 50 +++++ .../config/.prettierrc_java_plugin.yml | 3 + 10 files changed, 228 insertions(+), 39 deletions(-) create mode 100644 testlib/src/main/resources/npm/prettier/config/.prettierrc_java_plugin.yml diff --git a/CHANGES.md b/CHANGES.md index 1d78e8d932..652e4ce38c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +### Fixed +* Added support for plugins when using Prettier version `3.0.0` and newer. ([#1802](https://github.com/diffplug/spotless/pull/1802)) + ## [2.41.0] - 2023-08-29 ### Added * Add a `jsonPatch` step to `json` formatter configurations. This allows patching of JSON documents using [JSON Patches](https://jsonpatch.com). ([#1753](https://github.com/diffplug/spotless/pull/1753)) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java b/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java index ccdc189d27..a517a7219b 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java @@ -17,7 +17,9 @@ import java.io.File; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class PrettierRestService extends BaseNpmRestService { @@ -31,6 +33,16 @@ public String resolveConfig(File prettierConfigPath, Map prettie jsonProperties.put("prettier_config_path", prettierConfigPath.getAbsolutePath()); } if (prettierConfigOptions != null) { + // Prettier 3.x plugins support + if (prettierConfigOptions.get("plugins") instanceof List) { + try { + var pluginArray = (List) prettierConfigOptions.get("plugins"); + var pluginsJson = pluginArray.stream().map(e -> '"' + e + '"').collect(Collectors.joining(",", "[", "]")); + prettierConfigOptions.put("plugins", JsonRawValue.wrap(pluginsJson)); + } catch (ClassCastException e) { + throw new IllegalArgumentException("Only values of type 'List' are supported for plugins."); + } + } jsonProperties.put("prettier_config_options", SimpleJsonWriter.of(prettierConfigOptions).toJsonRawValue()); } diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index eab7e32b2d..989b4ece12 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -4,6 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +### Fixed +* Added support for plugins when using Prettier version `3.0.0` and newer. ([#1802](https://github.com/diffplug/spotless/pull/1802)) + ## [6.21.0] - 2023-08-29 ### Added * Add a `jsonPatch` step to `json` formatter configurations. This allows patching of JSON documents using [JSON Patches](https://jsonpatch.com). ([#1753](https://github.com/diffplug/spotless/pull/1753)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 944c07bb6e..2253557f3a 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -1024,10 +1024,12 @@ Since spotless uses the actual npm prettier package behind the scenes, it is pos spotless { java { prettier(['prettier': '2.8.8', 'prettier-plugin-java': '2.2.0']).config(['parser': 'java', 'tabWidth': 4]) + // prettier(['prettier': '3.0.3', 'prettier-plugin-java': '2.3.0']).config(['parser': 'java', 'tabWidth': 4, 'plugins': ['prettier-plugin-java']]) // Prettier v3 } format 'php', { target 'src/**/*.php' prettier(['prettier': '2.8.8', '@prettier/plugin-php': '0.19.6']).config(['parser': 'php', 'tabWidth': 3]) + // prettier(['prettier': '3.0.3', '@prettier/plugin-php': '0.20.1']).config(['parser': 'php', 'tabWidth': 3, 'plugins': ['@prettier/plugin-php']]) // Prettier v3 } } ``` diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java index 4d5069c1b5..ed32900db0 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java @@ -19,14 +19,22 @@ import org.assertj.core.api.Assertions; import org.gradle.testkit.runner.BuildResult; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import com.diffplug.spotless.npm.PrettierFormatterStep; import com.diffplug.spotless.tag.NpmTest; @NpmTest class PrettierIntegrationTest extends GradleIntegrationHarness { - @Test - void useInlineConfig() throws IOException { + + private static final String PRETTIER_VERSION_2 = PrettierFormatterStep.DEFAULT_VERSION; + + private static final String PRETTIER_VERSION_3 = "3.0.3"; + + @ParameterizedTest(name = "{index}: useInlineConfig with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void useInlineConfig(String prettierVersion) throws IOException { setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -38,17 +46,25 @@ void useInlineConfig() throws IOException { "spotless {", " format 'mytypescript', {", " target 'test.ts'", - " prettier().config(prettierConfig)", + " prettier('" + prettierVersion + "').config(prettierConfig)", " }", "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); - final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); + BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); - assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_2.clean"); + switch (prettierVersion) { + case PRETTIER_VERSION_2: + assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_2.clean"); + break; + case PRETTIER_VERSION_3: + assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_3.clean"); + break; + } } - @Test - void verifyCleanSpotlessCheckWorks() throws IOException { + @ParameterizedTest(name = "{index}: verifyCleanSpotlessCheckWorks with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void verifyCleanSpotlessCheckWorks(String prettierVersion) throws IOException { setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -60,7 +76,7 @@ void verifyCleanSpotlessCheckWorks() throws IOException { "spotless {", " format 'mytypescript', {", " target 'test.ts'", - " prettier().config(prettierConfig)", + " prettier('" + prettierVersion + "').config(prettierConfig)", " }", "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); @@ -71,8 +87,9 @@ void verifyCleanSpotlessCheckWorks() throws IOException { gradleRunner().withArguments("--stacktrace", "spotlessCheck").build(); } - @Test - void useFileConfig() throws IOException { + @ParameterizedTest(name = "{index}: useFileConfig with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void useFileConfig(String prettierVersion) throws IOException { setFile(".prettierrc.yml").toResource("npm/prettier/config/.prettierrc.yml"); setFile("build.gradle").toLines( "plugins {", @@ -82,17 +99,25 @@ void useFileConfig() throws IOException { "spotless {", " format 'mytypescript', {", " target 'test.ts'", - " prettier().configFile('.prettierrc.yml')", + " prettier('" + prettierVersion + "').configFile('.prettierrc.yml')", " }", "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); - assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_2.clean"); + switch (prettierVersion) { + case PRETTIER_VERSION_2: + assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_2.clean"); + break; + case PRETTIER_VERSION_3: + assertFile("test.ts").sameAsResource("npm/prettier/config/typescript.configfile_prettier_3.clean"); + break; + } } - @Test - void chooseParserBasedOnFilename() throws IOException { + @ParameterizedTest(name = "{index}: chooseParserBasedOnFilename with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void chooseParserBasedOnFilename(String prettierVersion) throws IOException { setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -101,7 +126,7 @@ void chooseParserBasedOnFilename() throws IOException { "spotless {", " format 'webResources', {", " target 'dirty.*'", - " prettier()", + " prettier('" + prettierVersion + "')", " }", "}"); setFile("dirty.json").toResource("npm/prettier/filename/dirty.json"); @@ -110,8 +135,20 @@ void chooseParserBasedOnFilename() throws IOException { assertFile("dirty.json").sameAsResource("npm/prettier/filename/clean.json"); } - @Test - void useJavaCommunityPlugin() throws IOException { + @ParameterizedTest(name = "{index}: useJavaCommunityPlugin with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void useJavaCommunityPlugin(String prettierVersion) throws IOException { + var prettierPluginJava = ""; + var prettierConfigPluginsStr = ""; + switch (prettierVersion) { + case PRETTIER_VERSION_2: + prettierPluginJava = "2.1.0"; // last version to support v2 + break; + case PRETTIER_VERSION_3: + prettierPluginJava = "2.3.0"; // latest to support v3 + prettierConfigPluginsStr = "prettierConfig['plugins'] = ['prettier-plugin-java']"; + break; + } setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -120,9 +157,10 @@ void useJavaCommunityPlugin() throws IOException { "def prettierConfig = [:]", "prettierConfig['tabWidth'] = 4", "prettierConfig['parser'] = 'java'", + prettierConfigPluginsStr, "def prettierPackages = [:]", - "prettierPackages['prettier'] = '2.8.8'", - "prettierPackages['prettier-plugin-java'] = '2.2.0'", + "prettierPackages['prettier'] = '" + prettierVersion + "'", + "prettierPackages['prettier-plugin-java'] = '" + prettierPluginJava + "'", "spotless {", " format 'java', {", " target 'JavaTest.java'", @@ -135,8 +173,42 @@ void useJavaCommunityPlugin() throws IOException { assertFile("JavaTest.java").sameAsResource("npm/prettier/plugins/java-test.clean"); } - @Test - void suggestsMissingJavaCommunityPlugin() throws IOException { + @ParameterizedTest(name = "{index}: useJavaCommunityPluginFileConfig with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void useJavaCommunityPluginFileConfig(String prettierVersion) throws IOException { + var prettierPluginJava = ""; + switch (prettierVersion) { + case PRETTIER_VERSION_2: + prettierPluginJava = "2.1.0"; // last version to support v2 + break; + case PRETTIER_VERSION_3: + prettierPluginJava = "2.3.0"; // latest to support v3 + break; + } + setFile(".prettierrc.yml").toResource("npm/prettier/config/.prettierrc_java_plugin.yml"); + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "def prettierPackages = [:]", + "prettierPackages['prettier'] = '" + prettierVersion + "'", + "prettierPackages['prettier-plugin-java'] = '" + prettierPluginJava + "'", + "spotless {", + " format 'java', {", + " target 'JavaTest.java'", + " prettier(prettierPackages).configFile('.prettierrc.yml')", + " }", + "}"); + setFile("JavaTest.java").toResource("npm/prettier/plugins/java-test.dirty"); + final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); + Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + assertFile("JavaTest.java").sameAsResource("npm/prettier/plugins/java-test.clean"); + } + + @ParameterizedTest(name = "{index}: suggestsMissingJavaCommunityPlugin with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void suggestsMissingJavaCommunityPlugin(String prettierVersion) throws IOException { setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -145,7 +217,7 @@ void suggestsMissingJavaCommunityPlugin() throws IOException { "def prettierConfig = [:]", "prettierConfig['tabWidth'] = 4", "def prettierPackages = [:]", - "prettierPackages['prettier'] = '2.8.8'", + "prettierPackages['prettier'] = '" + prettierVersion + "'", "spotless {", " format 'java', {", " target 'JavaTest.java'", @@ -158,8 +230,20 @@ void suggestsMissingJavaCommunityPlugin() throws IOException { Assertions.assertThat(spotlessApply.getOutput()).contains("prettier-plugin-java"); } - @Test - void usePhpCommunityPlugin() throws IOException { + @ParameterizedTest(name = "{index}: usePhpCommunityPlugin with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void usePhpCommunityPlugin(String prettierVersion) throws IOException { + var prettierPluginPhp = ""; + var prettierConfigPluginsStr = ""; + switch (prettierVersion) { + case PRETTIER_VERSION_2: + prettierPluginPhp = "0.19.7"; // last version to support v2 + break; + case PRETTIER_VERSION_3: + prettierPluginPhp = "0.20.1"; // latest to support v3 + prettierConfigPluginsStr = "prettierConfig['plugins'] = ['@prettier/plugin-php']"; + break; + } setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -168,9 +252,10 @@ void usePhpCommunityPlugin() throws IOException { "def prettierConfig = [:]", "prettierConfig['tabWidth'] = 3", "prettierConfig['parser'] = 'php'", + prettierConfigPluginsStr, "def prettierPackages = [:]", - "prettierPackages['prettier'] = '2.8.8'", - "prettierPackages['@prettier/plugin-php'] = '0.19.6'", + "prettierPackages['prettier'] = '" + prettierVersion + "'", + "prettierPackages['@prettier/plugin-php'] = '" + prettierPluginPhp + "'", "spotless {", " format 'php', {", " target 'php-example.php'", @@ -188,8 +273,25 @@ void usePhpCommunityPlugin() throws IOException { * * @see Issue #1162 on github */ - @Test - void usePhpAndJavaCommunityPlugin() throws IOException { + @ParameterizedTest(name = "{index}: usePhpAndJavaCommunityPlugin with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void usePhpAndJavaCommunityPlugin(String prettierVersion) throws IOException { + var prettierPluginJava = ""; + var prettierPluginPhp = ""; + var prettierConfigPluginsJavaStr = ""; + var prettierConfigPluginsPhpStr = ""; + switch (prettierVersion) { + case PRETTIER_VERSION_2: + prettierPluginJava = "2.1.0"; // last version to support v2 + prettierPluginPhp = "0.19.7"; // last version to support v2 + break; + case PRETTIER_VERSION_3: + prettierPluginJava = "2.3.0"; // latest to support v3 + prettierPluginPhp = "0.20.1"; // latest to support v3 + prettierConfigPluginsJavaStr = "prettierConfigJava['plugins'] = ['prettier-plugin-java']"; + prettierConfigPluginsPhpStr = "prettierConfigPhp['plugins'] = ['@prettier/plugin-php']"; + break; + } setFile("build.gradle").toLines( "plugins {", " id 'com.diffplug.spotless'", @@ -198,15 +300,17 @@ void usePhpAndJavaCommunityPlugin() throws IOException { "def prettierConfigPhp = [:]", "prettierConfigPhp['tabWidth'] = 3", "prettierConfigPhp['parser'] = 'php'", + prettierConfigPluginsPhpStr, "def prettierPackagesPhp = [:]", - "prettierPackagesPhp['prettier'] = '2.8.8'", - "prettierPackagesPhp['@prettier/plugin-php'] = '0.19.6'", + "prettierPackagesPhp['prettier'] = '" + prettierVersion + "'", + "prettierPackagesPhp['@prettier/plugin-php'] = '" + prettierPluginPhp + "'", "def prettierConfigJava = [:]", "prettierConfigJava['tabWidth'] = 4", "prettierConfigJava['parser'] = 'java'", + prettierConfigPluginsJavaStr, "def prettierPackagesJava = [:]", - "prettierPackagesJava['prettier'] = '2.8.8'", - "prettierPackagesJava['prettier-plugin-java'] = '2.2.0'", + "prettierPackagesJava['prettier'] = '" + prettierVersion + "'", + "prettierPackagesJava['prettier-plugin-java'] = '" + prettierPluginJava + "'", "spotless {", " format 'php', {", " target 'php-example.php'", @@ -227,8 +331,9 @@ void usePhpAndJavaCommunityPlugin() throws IOException { assertFile("JavaTest.java").sameAsResource("npm/prettier/plugins/java-test.clean"); } - @Test - void autodetectNpmrcFileConfig() throws IOException { + @ParameterizedTest(name = "{index}: autodetectNpmrcFileConfig with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void autodetectNpmrcFileConfig(String prettierVersion) throws IOException { setFile(".npmrc").toLines( "registry=https://i.do.not.exist.com", "fetch-timeout=250", @@ -245,7 +350,7 @@ void autodetectNpmrcFileConfig() throws IOException { "spotless {", " format 'mytypescript', {", " target 'test.ts'", - " prettier().config(prettierConfig)", + " prettier('" + prettierVersion + "').config(prettierConfig)", " }", "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); @@ -253,8 +358,9 @@ void autodetectNpmrcFileConfig() throws IOException { Assertions.assertThat(spotlessApply.getOutput()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); } - @Test - void pickupNpmrcFileConfig() throws IOException { + @ParameterizedTest(name = "{index}: autodetectNpmrcFileConfig with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void pickupNpmrcFileConfig(String prettierVersion) throws IOException { setFile(".custom_npmrc").toLines( "registry=https://i.do.not.exist.com", "fetch-timeout=250", @@ -271,7 +377,7 @@ void pickupNpmrcFileConfig() throws IOException { "spotless {", " format 'mytypescript', {", " target 'test.ts'", - " prettier().npmrc('.custom_npmrc').config(prettierConfig)", + " prettier('" + prettierVersion + "').npmrc('.custom_npmrc').config(prettierConfig)", " }", "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index f932806fcc..b624299e71 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -4,6 +4,9 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format ( ## [Unreleased] +### Fixed +* Added support for plugins when using Prettier version `3.0.0` and newer. ([#1802](https://github.com/diffplug/spotless/pull/1802)) + ## [2.39.0] - 2023-08-29 ### Added * Add a `jsonPatch` step to `json` formatter configurations. This allows patching of JSON documents using [JSON Patches](https://jsonpatch.com). ([#1753](https://github.com/diffplug/spotless/pull/1753)) diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 74872ef61f..1dc78a5667 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -1074,6 +1074,8 @@ You can use prettier in any language-specific format, but usually you will be cr ${project.basedir}/path/to/configfile true + + @prettier/plugin-php diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java index e92b2814bd..c6b3e46e3c 100644 --- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java +++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/Prettier.java @@ -85,6 +85,11 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) { if (Boolean.TRUE.toString().equalsIgnoreCase(entry.getValue()) || Boolean.FALSE.toString().equalsIgnoreCase(entry.getValue())) { return new AbstractMap.SimpleEntry<>(entry.getKey(), Boolean.parseBoolean(entry.getValue())); } + // Prettier v3 - plugins config will be a comma delimited list of plugins + if (entry.getKey().equals("plugins")) { + List values = entry.getValue().isEmpty() ? List.of() : Arrays.asList(entry.getValue().split(",")); + return new AbstractMap.SimpleEntry<>(entry.getKey(), values); + } return entry; }) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new)); diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java index 9cd1a313eb..abba35e72c 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java @@ -184,6 +184,56 @@ void custom_plugin() throws Exception { assertFile("php-example.php").sameAsResource("npm/prettier/plugins/php.clean"); } + @Test + void custom_plugin_prettier3() throws Exception { + writePomWithFormatSteps( + "php-example.php", + "", + " ", + " ", + " prettier", + " 3.0.3", + " ", + " ", + " @prettier/plugin-php", + " 0.20.1", + " ", + " ", + " ", + " 3", + " php", + " @prettier/plugin-php", + " ", + ""); + + setFile("php-example.php").toResource("npm/prettier/plugins/php.dirty"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile("php-example.php").sameAsResource("npm/prettier/plugins/php.clean"); + } + + @Test + void custom_plugin_prettier3_file_config() throws Exception { + writePomWithFormatSteps( + "JavaTest.java", + "", + " ", + " ", + " prettier", + " 3.0.3", + " ", + " ", + " prettier-plugin-java", + " 2.3.0", + " ", + " ", + " .prettierrc.yml", + ""); + setFile(".prettierrc.yml").toResource("npm/prettier/config/.prettierrc_java_plugin.yml"); + setFile("JavaTest.java").toResource("npm/prettier/plugins/java-test.dirty"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile("JavaTest.java").sameAsResource("npm/prettier/plugins/java-test.clean"); + } + @Test void autodetect_parser_based_on_filename() throws Exception { writePomWithFormatSteps( diff --git a/testlib/src/main/resources/npm/prettier/config/.prettierrc_java_plugin.yml b/testlib/src/main/resources/npm/prettier/config/.prettierrc_java_plugin.yml new file mode 100644 index 0000000000..3f7a801335 --- /dev/null +++ b/testlib/src/main/resources/npm/prettier/config/.prettierrc_java_plugin.yml @@ -0,0 +1,3 @@ +parser: java +tabWidth: 4 +plugins: ['prettier-plugin-java'] From d5db9148e47a61e4f814af58b90228414cd2b833 Mon Sep 17 00:00:00 2001 From: samypr100 <3933065+samypr100@users.noreply.github.com> Date: Sat, 2 Sep 2023 23:27:21 -0400 Subject: [PATCH 2/5] fix: add final back to BuildResult --- .../com/diffplug/gradle/spotless/PrettierIntegrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java index ed32900db0..74b6db9167 100644 --- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java +++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/PrettierIntegrationTest.java @@ -50,7 +50,7 @@ void useInlineConfig(String prettierVersion) throws IOException { " }", "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); - BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); + final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); switch (prettierVersion) { case PRETTIER_VERSION_2: @@ -80,7 +80,7 @@ void verifyCleanSpotlessCheckWorks(String prettierVersion) throws IOException { " }", "}"); setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); - BuildResult spotlessCheckFailsGracefully = gradleRunner().withArguments("--stacktrace", "spotlessCheck").buildAndFail(); + final BuildResult spotlessCheckFailsGracefully = gradleRunner().withArguments("--stacktrace", "spotlessCheck").buildAndFail(); Assertions.assertThat(spotlessCheckFailsGracefully.getOutput()).contains("> The following files had format violations:"); gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); From 3226165b74c32c00dcdce8deeecbf7c23283fe3c Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Sun, 3 Sep 2023 20:22:00 +0200 Subject: [PATCH 3/5] feat: add support for nested lists in json writer opt for supporting lists/arrays as first level citizen in json serialization for configs in npm-based formatters. --- .../diffplug/spotless/npm/JsonEscaper.java | 18 +++++- ...{SimpleJsonWriter.java => JsonWriter.java} | 33 +++++++---- .../spotless/npm/ListableAdapter.java | 58 +++++++++++++++++++ .../spotless/npm/PrettierRestService.java | 15 +---- .../spotless/npm/SimpleRestClient.java | 4 +- .../spotless/npm/TsFmtFormatterStep.java | 2 +- .../spotless/npm/TsFmtRestService.java | 2 +- ...sonWriterTest.java => JsonWriterTest.java} | 6 +- 8 files changed, 106 insertions(+), 32 deletions(-) rename lib/src/main/java/com/diffplug/spotless/npm/{SimpleJsonWriter.java => JsonWriter.java} (77%) create mode 100644 lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java rename testlib/src/test/java/com/diffplug/spotless/npm/{SimpleJsonWriterTest.java => JsonWriterTest.java} (93%) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/JsonEscaper.java b/lib/src/main/java/com/diffplug/spotless/npm/JsonEscaper.java index 163818d0e7..3ac20d892b 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/JsonEscaper.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/JsonEscaper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,22 @@ public static String jsonEscape(Object val) { if (val instanceof String) { return jsonEscape((String) val); } + if (ListableAdapter.canAdapt(val)) { + // create an array + StringBuilder sb = new StringBuilder(); + sb.append('['); + boolean first = true; + for (Object o : ListableAdapter.adapt(val)) { + if (first) { + first = false; + } else { + sb.append(", "); + } + sb.append(jsonEscape(o)); + } + sb.append(']'); + return sb.toString(); + } return val.toString(); } diff --git a/lib/src/main/java/com/diffplug/spotless/npm/SimpleJsonWriter.java b/lib/src/main/java/com/diffplug/spotless/npm/JsonWriter.java similarity index 77% rename from lib/src/main/java/com/diffplug/spotless/npm/SimpleJsonWriter.java rename to lib/src/main/java/com/diffplug/spotless/npm/JsonWriter.java index 846f7f1cf3..bbdf9b63d4 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/SimpleJsonWriter.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/JsonWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2020 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,33 +28,46 @@ import com.diffplug.spotless.ThrowingEx; -public class SimpleJsonWriter { +class JsonWriter { private final LinkedHashMap valueMap = new LinkedHashMap<>(); - public static SimpleJsonWriter of(Map values) { - SimpleJsonWriter writer = new SimpleJsonWriter(); + public static JsonWriter of(Map values) { + JsonWriter writer = new JsonWriter(); writer.putAll(values); return writer; } - SimpleJsonWriter putAll(Map values) { + JsonWriter putAll(Map values) { verifyValues(values); this.valueMap.putAll(values); return this; } - SimpleJsonWriter put(String name, Object value) { + JsonWriter put(String name, Object value) { verifyValues(Collections.singletonMap(name, value)); this.valueMap.put(name, value); return this; } private void verifyValues(Map values) { - if (values.values() - .stream() - .anyMatch(val -> !(val instanceof String || val instanceof JsonRawValue || val instanceof Number || val instanceof Boolean))) { - throw new IllegalArgumentException("Only values of type 'String', 'JsonRawValue', 'Number' and 'Boolean' are supported. You provided: " + values.values()); + for (Object value : values.values()) { + verifyValue(value); + } + } + + private void verifyValue(Object val) { + if (val == null) { + return; + } + if (ListableAdapter.canAdapt(val)) { + for (Object o : ListableAdapter.adapt(val)) { + verifyValue(o); + } + return; + } + if (!(val instanceof String || val instanceof JsonRawValue || val instanceof Number || val instanceof Boolean)) { + throw new IllegalArgumentException("Only values of type 'String', 'JsonRawValue', 'Number' and 'Boolean' are supported. You provided: " + val); } } diff --git a/lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java b/lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java new file mode 100644 index 0000000000..3e05e8e51c --- /dev/null +++ b/lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023 DiffPlug + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.diffplug.spotless.npm; + +import javax.annotation.Nonnull; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +class ListableAdapter implements Iterable { + + private final List delegate; + + @SuppressWarnings("unchecked") + private ListableAdapter(Object delegate) { + Objects.requireNonNull(delegate); + if (!canAdapt(delegate)) { + throw new IllegalArgumentException("Cannot create ListableAdapter from " + delegate.getClass() + ". Use canAdapt() to check first."); + } + if (delegate instanceof List) { + this.delegate = (List) delegate; + } else if (delegate.getClass().isArray()) { + this.delegate = Arrays.asList((T[]) delegate); + } else { + throw new IllegalArgumentException("Cannot create IterableAdapter from " + delegate.getClass()); + } + } + + static Iterable adapt(Object delegate) { + return new ListableAdapter<>(delegate); + } + + @Override + @Nonnull + public Iterator iterator() { + return delegate.iterator(); + } + + static boolean canAdapt(Object delegate) { + Objects.requireNonNull(delegate); + return delegate instanceof List || delegate.getClass().isArray(); + } +} diff --git a/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java b/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java index a517a7219b..11fd29c68a 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java @@ -17,9 +17,7 @@ import java.io.File; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; -import java.util.stream.Collectors; public class PrettierRestService extends BaseNpmRestService { @@ -33,18 +31,7 @@ public String resolveConfig(File prettierConfigPath, Map prettie jsonProperties.put("prettier_config_path", prettierConfigPath.getAbsolutePath()); } if (prettierConfigOptions != null) { - // Prettier 3.x plugins support - if (prettierConfigOptions.get("plugins") instanceof List) { - try { - var pluginArray = (List) prettierConfigOptions.get("plugins"); - var pluginsJson = pluginArray.stream().map(e -> '"' + e + '"').collect(Collectors.joining(",", "[", "]")); - prettierConfigOptions.put("plugins", JsonRawValue.wrap(pluginsJson)); - } catch (ClassCastException e) { - throw new IllegalArgumentException("Only values of type 'List' are supported for plugins."); - } - } - jsonProperties.put("prettier_config_options", SimpleJsonWriter.of(prettierConfigOptions).toJsonRawValue()); - + jsonProperties.put("prettier_config_options", JsonWriter.of(prettierConfigOptions).toJsonRawValue()); } return restClient.postJson("/prettier/config-options", jsonProperties); } diff --git a/lib/src/main/java/com/diffplug/spotless/npm/SimpleRestClient.java b/lib/src/main/java/com/diffplug/spotless/npm/SimpleRestClient.java index 561839c757..2f413e4b3a 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/SimpleRestClient.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/SimpleRestClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,7 @@ static SimpleRestClient forBaseUrl(String baseUrl) { } String postJson(String endpoint, Map jsonParams) throws SimpleRestException { - final SimpleJsonWriter jsonWriter = SimpleJsonWriter.of(jsonParams); + final JsonWriter jsonWriter = JsonWriter.of(jsonParams); final String jsonString = jsonWriter.toJsonString(); return postJson(endpoint, jsonString); diff --git a/lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java b/lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java index a83c3e202a..6b55610be0 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java @@ -107,7 +107,7 @@ private Map unifyOptions() { Map unified = new HashMap<>(); if (!this.inlineTsFmtSettings.isEmpty()) { File targetFile = new File(this.buildDir, "inline-tsfmt.json"); - SimpleJsonWriter.of(this.inlineTsFmtSettings).toJsonFile(targetFile); + JsonWriter.of(this.inlineTsFmtSettings).toJsonFile(targetFile); unified.put("tsfmt", true); unified.put("tsfmtFile", targetFile.getAbsolutePath()); } else if (this.configFile != null) { diff --git a/lib/src/main/java/com/diffplug/spotless/npm/TsFmtRestService.java b/lib/src/main/java/com/diffplug/spotless/npm/TsFmtRestService.java index 704d2b47af..61a53b4637 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/TsFmtRestService.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/TsFmtRestService.java @@ -28,7 +28,7 @@ public String format(String fileContent, Map configOptions) { Map jsonProperties = new LinkedHashMap<>(); jsonProperties.put("file_content", fileContent); if (configOptions != null && !configOptions.isEmpty()) { - jsonProperties.put("config_options", SimpleJsonWriter.of(configOptions).toJsonRawValue()); + jsonProperties.put("config_options", JsonWriter.of(configOptions).toJsonRawValue()); } return restClient.postJson("/tsfmt/format", jsonProperties); diff --git a/testlib/src/test/java/com/diffplug/spotless/npm/SimpleJsonWriterTest.java b/testlib/src/test/java/com/diffplug/spotless/npm/JsonWriterTest.java similarity index 93% rename from testlib/src/test/java/com/diffplug/spotless/npm/SimpleJsonWriterTest.java rename to testlib/src/test/java/com/diffplug/spotless/npm/JsonWriterTest.java index 34d7966709..cb1719c0f3 100644 --- a/testlib/src/test/java/com/diffplug/spotless/npm/SimpleJsonWriterTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/npm/JsonWriterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,9 @@ import com.diffplug.common.collect.ImmutableMap; import com.diffplug.spotless.ResourceHarness; -class SimpleJsonWriterTest extends ResourceHarness { +class JsonWriterTest extends ResourceHarness { - private SimpleJsonWriter jsonWriter = new SimpleJsonWriter(); + private JsonWriter jsonWriter = new JsonWriter(); @Test void itWritesAValidEmptyObject() { From 6fbb6505790be5103a96a4385eb33095046e1163 Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Sun, 3 Sep 2023 20:32:58 +0200 Subject: [PATCH 4/5] docs: make explicit and add maven doc --- plugin-gradle/README.md | 4 ++-- plugin-maven/README.md | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 2253557f3a..fcdcfc213a 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -1024,12 +1024,12 @@ Since spotless uses the actual npm prettier package behind the scenes, it is pos spotless { java { prettier(['prettier': '2.8.8', 'prettier-plugin-java': '2.2.0']).config(['parser': 'java', 'tabWidth': 4]) - // prettier(['prettier': '3.0.3', 'prettier-plugin-java': '2.3.0']).config(['parser': 'java', 'tabWidth': 4, 'plugins': ['prettier-plugin-java']]) // Prettier v3 + // prettier(['prettier': '3.0.3', 'prettier-plugin-java': '2.3.0']).config(['parser': 'java', 'tabWidth': 4, 'plugins': ['prettier-plugin-java']]) // Prettier v3 requires additional 'plugins' config } format 'php', { target 'src/**/*.php' prettier(['prettier': '2.8.8', '@prettier/plugin-php': '0.19.6']).config(['parser': 'php', 'tabWidth': 3]) - // prettier(['prettier': '3.0.3', '@prettier/plugin-php': '0.20.1']).config(['parser': 'php', 'tabWidth': 3, 'plugins': ['@prettier/plugin-php']]) // Prettier v3 + // prettier(['prettier': '3.0.3', '@prettier/plugin-php': '0.20.1']).config(['parser': 'php', 'tabWidth': 3, 'plugins': ['@prettier/plugin-php']]) // Prettier v3 requires additional 'plugins' config } } ``` diff --git a/plugin-maven/README.md b/plugin-maven/README.md index 1dc78a5667..8f91d8b08b 100644 --- a/plugin-maven/README.md +++ b/plugin-maven/README.md @@ -1121,6 +1121,7 @@ Since spotless uses the actual npm prettier package behind the scenes, it is pos 4 java + prettier-plugin-java @@ -1146,6 +1147,7 @@ Since spotless uses the actual npm prettier package behind the scenes, it is pos 3 php + @prettier/plugin-php From 3754eb12d3da00be2da0cdadd3123e11ae63af9b Mon Sep 17 00:00:00 2001 From: Simon Gamma Date: Mon, 4 Sep 2023 15:02:11 +0200 Subject: [PATCH 5/5] style: fix import order --- .../main/java/com/diffplug/spotless/npm/ListableAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java b/lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java index 3e05e8e51c..24ae62fde6 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/ListableAdapter.java @@ -15,13 +15,13 @@ */ package com.diffplug.spotless.npm; -import javax.annotation.Nonnull; - import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Objects; +import javax.annotation.Nonnull; + class ListableAdapter implements Iterable { private final List delegate;