diff --git a/lib/src/main/java/com/diffplug/spotless/npm/PrettierConfig.java b/lib/src/main/java/com/diffplug/spotless/npm/PrettierConfig.java index 8a51910205..5bce2726e9 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/PrettierConfig.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/PrettierConfig.java @@ -32,9 +32,12 @@ public class PrettierConfig implements Serializable { private final TreeMap options; - public PrettierConfig(@Nullable File prettierConfigPath, @Nullable Map options) { + private final Boolean editorconfig; + + public PrettierConfig(@Nullable File prettierConfigPath, @Nullable Map options, @Nullable Boolean editorconfig) { this.prettierConfigPathSignature = prettierConfigPath == null ? null : FileSignature.promise(prettierConfigPath); this.options = options == null ? new TreeMap<>() : new TreeMap<>(options); + this.editorconfig = editorconfig; } @Nullable @@ -45,4 +48,9 @@ public File getPrettierConfigPath() { public Map getOptions() { return new TreeMap<>(this.options); } + + @Nullable + public Boolean getEditorconfig() { + return editorconfig; + } } diff --git a/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java b/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java index 27a1002df5..472a2c11a3 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java @@ -90,7 +90,7 @@ public FormatterFunc createFormatterFunc() { logger.info("creating formatter function (starting server)"); ServerProcessInfo prettierRestServer = toRuntime().npmRunServer(); PrettierRestService restService = new PrettierRestService(prettierRestServer.getBaseUrl()); - String prettierConfigOptions = restService.resolveConfig(this.prettierConfig.getPrettierConfigPath(), this.prettierConfig.getOptions()); + String prettierConfigOptions = restService.resolveConfig(this.prettierConfig.getPrettierConfigPath(), this.prettierConfig.getOptions(), prettierConfig.getEditorconfig()); return Closeable.ofDangerous(() -> endServer(restService, prettierRestServer), new PrettierFilePathPassingFormatterFunc(prettierConfigOptions, restService)); } catch (IOException e) { throw ThrowingEx.asRuntime(e); 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 11fd29c68a..c6e4105178 100644 --- a/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java +++ b/lib/src/main/java/com/diffplug/spotless/npm/PrettierRestService.java @@ -25,7 +25,7 @@ public class PrettierRestService extends BaseNpmRestService { super(baseUrl); } - public String resolveConfig(File prettierConfigPath, Map prettierConfigOptions) { + public String resolveConfig(File prettierConfigPath, Map prettierConfigOptions, Boolean editorconfig) { Map jsonProperties = new LinkedHashMap<>(); if (prettierConfigPath != null) { jsonProperties.put("prettier_config_path", prettierConfigPath.getAbsolutePath()); @@ -33,6 +33,9 @@ public String resolveConfig(File prettierConfigPath, Map prettie if (prettierConfigOptions != null) { jsonProperties.put("prettier_config_options", JsonWriter.of(prettierConfigOptions).toJsonRawValue()); } + if (editorconfig != null) { + jsonProperties.put("editorconfig", editorconfig); + } return restClient.postJson("/prettier/config-options", jsonProperties); } diff --git a/lib/src/main/resources/com/diffplug/spotless/npm/prettier-serve.js b/lib/src/main/resources/com/diffplug/spotless/npm/prettier-serve.js index ac1f26790d..b885635211 100644 --- a/lib/src/main/resources/com/diffplug/spotless/npm/prettier-serve.js +++ b/lib/src/main/resources/com/diffplug/spotless/npm/prettier-serve.js @@ -5,19 +5,14 @@ app.post("/prettier/config-options", (req, res) => { const prettier_config_path = config_data.prettier_config_path; const prettier_config_options = config_data.prettier_config_options || {}; - if (prettier_config_path) { - prettier - .resolveConfig(undefined, { config: prettier_config_path }) - .then(options => { - const mergedConfigOptions = mergeConfigOptions(options, prettier_config_options); - res.set("Content-Type", "application/json") - res.json(mergedConfigOptions); - }) - .catch(reason => res.status(501).send("Exception while resolving config_file_path: " + reason)); - return; - } - res.set("Content-Type", "application/json") - res.json(prettier_config_options); + prettier + .resolveConfig(prettier_config_path, { editorconfig: config_data.editorconfig }) + .then(options => { + const mergedConfigOptions = mergeConfigOptions(options, prettier_config_options); + res.set("Content-Type", "application/json") + res.json(mergedConfigOptions); + }) + .catch(reason => res.status(501).send("Exception while resolving config_file_path: " + reason)); }); app.post("/prettier/format", async (req, res) => { diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java index 59898cbf56..988b35c9ba 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java @@ -769,6 +769,9 @@ public class PrettierConfig extends NpmStepConfig { @Nullable Map prettierConfig; + @Nullable + Boolean editorconfig; + final Map devDependencies; PrettierConfig(Map devDependencies) { @@ -788,6 +791,12 @@ public PrettierConfig config(final Map prettierConfig) { return this; } + public PrettierConfig editorconfig(Boolean editorconfig) { + this.editorconfig = editorconfig; + replaceStep(); + return this; + } + @Override protected FormatterStep createStep() { final Project project = getProject(); @@ -797,7 +806,7 @@ protected FormatterStep createStep() { Arrays.asList(project.getProjectDir(), project.getRootDir())), new com.diffplug.spotless.npm.PrettierConfig( this.prettierConfigFile != null ? project.file(this.prettierConfigFile) : null, - this.prettierConfig)); + this.prettierConfig, this.editorconfig)); } } 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 b6547204b8..6ee13c54cd 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 @@ -115,6 +115,35 @@ void useFileConfig(String prettierVersion) throws IOException { } } + @ParameterizedTest(name = "{index}: useEditorconfig with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void useEditorconfig(String prettierVersion) throws IOException { + setFile(".prettierrc.yml").toResource("npm/prettier/config/.prettierrc_noop.yml"); + setFile(".editorconfig").toResource("npm/prettier/config/.editorconfig_20"); + setFile("build.gradle").toLines( + "plugins {", + " id 'com.diffplug.spotless'", + "}", + "repositories { mavenCentral() }", + "spotless {", + " format 'mytypescript', {", + " target 'test.ts'", + " prettier('" + prettierVersion + "').configFile('.prettierrc.yml').editorconfig(true)", + " }", + "}"); + setFile("test.ts").toResource("npm/prettier/config/typescript.dirty"); + final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").build(); + Assertions.assertThat(spotlessApply.getOutput()).contains("BUILD SUCCESSFUL"); + 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; + } + } + @ParameterizedTest(name = "{index}: chooseParserBasedOnFilename with prettier {0}") @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) void chooseParserBasedOnFilename(String prettierVersion) throws IOException { 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 c6b3e46e3c..0af813bc9a 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 @@ -47,6 +47,9 @@ public class Prettier extends AbstractNpmFormatterStepFactory { @Parameter private String configFile; + @Parameter + private Boolean editorconfig; + @Override public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) { @@ -101,7 +104,7 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) { File baseDir = baseDir(stepConfig); File buildDir = buildDir(stepConfig); File cacheDir = cacheDir(stepConfig); - PrettierConfig prettierConfig = new PrettierConfig(configFileHandler, configInline); + PrettierConfig prettierConfig = new PrettierConfig(configFileHandler, configInline, editorconfig); NpmPathResolver npmPathResolver = npmPathResolver(stepConfig); return PrettierFormatterStep.create(devDependencies, stepConfig.getProvisioner(), baseDir, buildDir, cacheDir, npmPathResolver, prettierConfig); } 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 abba35e72c..ceaff92674 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 @@ -158,6 +158,25 @@ void multiple_prettier_configs() throws Exception { } + @Test + void prettier_editorconfig() throws Exception { + String suffix = "ts"; + writePomWithPrettierSteps("**/*." + suffix, + "", + " 1.16.4", + " .prettierrc.yml", + " true", + ""); + + String kind = "typescript"; + setFile(".prettierrc.yml").toResource("npm/prettier/config/.prettierrc_noop.yml"); + setFile(".editorconfig").toResource("npm/prettier/config/.editorconfig_300"); + String path = "src/main/" + kind + "/test." + suffix; + setFile(path).toResource("npm/prettier/filetypes/" + kind + "/" + kind + ".dirty"); + mavenRunner().withArguments("spotless:apply").runNoError(); + assertFile(path).sameAsResource("npm/prettier/filetypes/" + kind + "/" + kind + ".clean"); + } + @Test void custom_plugin() throws Exception { writePomWithFormatSteps( diff --git a/testlib/src/main/resources/npm/prettier/config/.editorconfig_20 b/testlib/src/main/resources/npm/prettier/config/.editorconfig_20 new file mode 100644 index 0000000000..8984b96358 --- /dev/null +++ b/testlib/src/main/resources/npm/prettier/config/.editorconfig_20 @@ -0,0 +1,2 @@ +[*] +max_line_length = 20 diff --git a/testlib/src/main/resources/npm/prettier/config/.editorconfig_300 b/testlib/src/main/resources/npm/prettier/config/.editorconfig_300 new file mode 100644 index 0000000000..2d70e3af58 --- /dev/null +++ b/testlib/src/main/resources/npm/prettier/config/.editorconfig_300 @@ -0,0 +1,2 @@ +[*] +max_line_length = 300 diff --git a/testlib/src/main/resources/npm/prettier/config/.prettierrc_noop.yml b/testlib/src/main/resources/npm/prettier/config/.prettierrc_noop.yml new file mode 100644 index 0000000000..dc710caa92 --- /dev/null +++ b/testlib/src/main/resources/npm/prettier/config/.prettierrc_noop.yml @@ -0,0 +1 @@ +parser: typescript diff --git a/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.java b/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.java index 54ce09e7e8..6261df1166 100644 --- a/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/npm/PrettierFormatterStepTest.java @@ -69,7 +69,7 @@ private void runTestUsingPrettier(String fileType, Map dependenc buildDir(), null, npmPathResolver(), - new PrettierConfig(prettierRc, null)); + new PrettierConfig(prettierRc, null, null)); try (StepHarness stepHarness = StepHarness.forStep(formatterStep)) { stepHarness.testResource(dirtyFile, cleanFile); @@ -96,7 +96,7 @@ void parserInferenceBasedOnExplicitFilepathIsWorking(String prettierVersion) thr buildDir(), null, npmPathResolver(), - new PrettierConfig(null, ImmutableMap.of("filepath", "anyname.json"))); // should select parser based on this name + new PrettierConfig(null, ImmutableMap.of("filepath", "anyname.json"), null)); // should select parser based on this name try (StepHarness stepHarness = StepHarness.forStep(formatterStep)) { stepHarness.testResource(dirtyFile, cleanFile); @@ -118,7 +118,7 @@ void parserInferenceBasedOnFilenameIsWorking(String prettierVersion) throws Exce buildDir(), null, npmPathResolver(), - new PrettierConfig(null, Collections.emptyMap())); + new PrettierConfig(null, Collections.emptyMap(), null)); try (StepHarnessWithFile stepHarness = StepHarnessWithFile.forStep(this, formatterStep)) { stepHarness.testResource("test.json", dirtyFile, cleanFile); @@ -134,7 +134,7 @@ void verifyPrettierErrorMessageIsRelayed() throws Exception { buildDir(), null, npmPathResolver(), - new PrettierConfig(null, ImmutableMap.of("parser", "postcss"))); + new PrettierConfig(null, ImmutableMap.of("parser", "postcss"), null)); try (StepHarnessWithFile stepHarness = StepHarnessWithFile.forStep(this, formatterStep)) { stepHarness.expectLintsOfResource("npm/prettier/filetypes/scss/scss.dirty") .toBe("LINE_UNDEFINED prettier-format(com.diffplug.spotless.npm.SimpleRestClient$SimpleRestResponseException) Unexpected response status code at /prettier/format [HTTP 500] -- (Error while formatting: Error: Couldn't resolve parser \"postcss\") (...)"); @@ -170,19 +170,27 @@ void runFormatTest(String prettierVersion, PrettierConfig config, String cleanFi @ParameterizedTest(name = "{index}: defaults are applied with prettier {0}") @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) void defaultsAreApplied(String prettierVersion) throws Exception { - runFormatTest(prettierVersion, new PrettierConfig(null, ImmutableMap.of("parser", "typescript")), "defaults_prettier_" + major(prettierVersion)); + runFormatTest(prettierVersion, new PrettierConfig(null, ImmutableMap.of("parser", "typescript"), null), "defaults_prettier_" + major(prettierVersion)); } @ParameterizedTest(name = "{index}: config file options are applied with prettier {0}") @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) void configFileOptionsAreApplied(String prettierVersion) throws Exception { - runFormatTest(prettierVersion, new PrettierConfig(createTestFile(FILEDIR + ".prettierrc.yml"), null), "configfile_prettier_" + major(prettierVersion)); + runFormatTest(prettierVersion, new PrettierConfig(createTestFile(FILEDIR + ".prettierrc.yml"), null, null), "configfile_prettier_" + major(prettierVersion)); } - @ParameterizedTest(name = "{index}: config file options can be overriden with prettier {0}") + @ParameterizedTest(name = "{index}: config file options can be overridden with prettier {0}") @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) - void configFileOptionsCanBeOverriden(String prettierVersion) throws Exception { - runFormatTest(prettierVersion, new PrettierConfig(createTestFile(FILEDIR + ".prettierrc.yml"), ImmutableMap.of("printWidth", 300)), "override_prettier_" + major(prettierVersion)); + void configFileOptionsCanBeOverridden(String prettierVersion) throws Exception { + runFormatTest(prettierVersion, new PrettierConfig(createTestFile(FILEDIR + ".prettierrc.yml"), ImmutableMap.of("printWidth", 300), null), "override_prettier_" + major(prettierVersion)); + } + + @ParameterizedTest(name = "{index}: config file options can be extended with editorconfig with prettier {0}") + @ValueSource(strings = {PRETTIER_VERSION_2, PRETTIER_VERSION_3}) + void configFileOptionsCanBeExtendedWithEditorconfig(String prettierVersion) throws Exception { + setFile(".editorconfig").toResource(FILEDIR + ".editorconfig_300"); + File prettierConfigFile = setFile(".prettierrc.yml").toResource(FILEDIR + ".prettierrc_noop.yml"); + runFormatTest(prettierVersion, new PrettierConfig(prettierConfigFile, null, true), "override_prettier_" + major(prettierVersion)); } private String major(String semVer) { @@ -194,7 +202,7 @@ private String major(String semVer) { void equality() { new SerializableEqualityTester() { String prettierVersion = "3.0.0"; - PrettierConfig config = new PrettierConfig(null, Map.of("parser", "typescript")); + PrettierConfig config = new PrettierConfig(null, Map.of("parser", "typescript"), null); @Override protected void setupTest(API api) { @@ -203,7 +211,7 @@ protected void setupTest(API api) { // change the groupArtifact, and it's different prettierVersion = "2.8.8"; api.areDifferentThan(); - config = new PrettierConfig(null, Map.of("parser", "css")); + config = new PrettierConfig(null, Map.of("parser", "css"), null); api.areDifferentThan(); }