Skip to content

Commit

Permalink
add support for prettier-plugins to maven-builds and document in README
Browse files Browse the repository at this point in the history
  • Loading branch information
simschla committed Jun 12, 2020
1 parent 8eff924 commit 8cbbb27
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 31 deletions.
74 changes: 68 additions & 6 deletions plugin-maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,13 +287,21 @@ To use prettier, you first have to specify the files that you want it to apply t
</includes>

<prettier>
<!-- Specify either simple prettier version (1.19.0 is max supported,
which is also default) or whole devDependencies -->
<!-- Specify at most one of the following 3 configs: either 'prettierVersion' (2.0.5 is default), 'devDependencies' or 'devDependencyProperties' -->
<prettierVersion>1.19.0</prettierVersion>
<devDependencies>
<prettier>1.19.0</prettier>
</devDependencies>

<devDependencyProperties>
<property>
<name>prettier</name>
<value>2.0.5</value>
</property>
<property>
<name>@prettier/plugin-php</name> <!-- this could not be written in the simpler to write 'devDependencies' element. -->
<value>0.14.2</value>
</property>
</devDependencyProperties>
<!-- Specify config file and/or inline config -->
<configFile>${basedir}/path/to/configfile</configFile>
<config>
Expand All @@ -315,6 +323,62 @@ Supported config file variants are documented on [prettier.io](https://prettier.

To apply prettier to more kinds of files, just add more formats.

<a name="prettier-plugins"></a>
### Using plugins for prettier

Since spotless uses the actual npm prettier package behind the scenes, it is possible to use prettier with
[plugins](https://prettier.io/docs/en/plugins.html#official-plugins) or [community-plugins](https://www.npmjs.com/search?q=prettier-plugin) in order to support even more file types.

```xml
<configuration>
<formats>
<!-- prettier with java-plugin -->
<format>
<includes>
<include>src/*/java/**/*.java</include>
</includes>

<prettier>
<devDependencies>
<prettier>2.0.5</prettier>
<prettier-plugin-java>0.8.0</prettier-plugin-java>
</devDependencies>
<config>
<tabWidth>4</tabWidth>
<parser>java</parser>
</config>
</prettier>
</format>

<!-- prettier with php-plugin -->
<format>
<includes>
<include>src/**/*.php</include>
</includes>

<prettier>
<!-- use the devDependencyProperties writing style when the property-names are not well-formed such as @prettier/plugin-php -->
<devDependencyProperties>
<property>
<name>prettier</name>
<value>2.0.5</value>
</property>
<property>
<name>@prettier/plugin-php</name>
<value>0.14.2</value>
</property>
</devDependencyProperties>
<config>
<tabWidth>3</tabWidth>
<parser>php</parser>
</config>
</prettier>
</format>

</formats>
</configuration>
```

### Prerequisite: prettier requires a working NodeJS version

Prettier, like tsfmt, is based on NodeJS, so to use it, a working NodeJS installation (especially npm) is required on the host running spotless.
Expand All @@ -326,9 +390,7 @@ Spotless will try to auto-discover an npm installation. If that is not working f
...
```

Spotless uses npm to install necessary packages locally. It runs prettier using [J2V8](https://github.com/eclipsesource/J2V8) internally after that.
Development for J2V8 for non android envs is stopped (for Windows since J2V8 4.6.0 and Unix 4.8.0), therefore Prettier is limited to <= v1.19.0 as newer versions
use ES6 feature and that needs a newer J2V8 version.
Spotless uses npm to install necessary packages and to run the prettier formatter after that.

<a name="format"></a>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 DiffPlug
* Copyright 2016-2020 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,8 +16,8 @@
package com.diffplug.spotless.maven.generic;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.maven.plugins.annotations.Parameter;

Expand All @@ -35,6 +35,9 @@ public class Prettier implements FormatterStepFactory {
@Parameter
private Map<String, String> devDependencies;

@Parameter
private Properties devDependencyProperties;

@Parameter
private Map<String, String> config;

Expand All @@ -48,17 +51,17 @@ public class Prettier implements FormatterStepFactory {
public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {

// check if config is only setup in one way
if (this.prettierVersion != null && this.devDependencies != null) {
if (moreThanOneNonNull(this.prettierVersion, this.devDependencies, this.devDependencyProperties)) {
throw onlyOneConfig();
}

// set dev dependencies
if (devDependencies == null) {
if (prettierVersion == null || prettierVersion.isEmpty()) {
devDependencies = PrettierFormatterStep.defaultDevDependencies();
} else {
devDependencies = PrettierFormatterStep.defaultDevDependenciesWithPrettier(prettierVersion);
}
devDependencies = PrettierFormatterStep.defaultDevDependencies(); // fallback
}

if (prettierVersion != null && !prettierVersion.isEmpty()) {
this.devDependencies = PrettierFormatterStep.defaultDevDependenciesWithPrettier(prettierVersion);
} else if (devDependencyProperties != null) {
this.devDependencies = dependencyPropertiesAsMap();
}

File npm = npmExecutable != null ? stepConfig.getFileLocator().locateFile(npmExecutable) : null;
Expand All @@ -73,19 +76,20 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {

Map<String, Object> configInline;
if (config != null) {
configInline = new LinkedHashMap<>();
// try to parse string values as integers or booleans
for (Map.Entry<String, String> e : config.entrySet()) {
try {
configInline.put(e.getKey(), Integer.parseInt(e.getValue()));
} catch (NumberFormatException ignore) {
try {
configInline.put(e.getKey(), Boolean.parseBoolean(e.getValue()));
} catch (IllegalArgumentException ignore2) {
configInline.put(e.getKey(), e.getValue());
}
}
}
configInline = config.entrySet().stream()
.map(entry -> {
try {
Integer value = Integer.parseInt(entry.getValue());
return new AbstractMap.SimpleEntry<>(entry.getKey(), value);
} catch (NumberFormatException ignore) {
// ignored
}
if (Boolean.TRUE.toString().equalsIgnoreCase(entry.getValue()) || Boolean.FALSE.toString().equalsIgnoreCase(entry.getValue())) {
return new AbstractMap.SimpleEntry<>(entry.getKey(), Boolean.parseBoolean(entry.getValue()));
}
return entry;
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new));
} else {
configInline = null;
}
Expand All @@ -96,7 +100,21 @@ public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {
return PrettierFormatterStep.create(devDependencies, stepConfig.getProvisioner(), buildDir, npm, prettierConfig);
}

private boolean moreThanOneNonNull(Object... objects) {
return Arrays.stream(objects)
.filter(Objects::nonNull)
.filter(o -> !(o instanceof String) || !((String) o).isEmpty()) // if it is a string, it should not be empty
.count() > 1;
}

private Map<String, String> dependencyPropertiesAsMap() {
return this.devDependencyProperties.stringPropertyNames()
.stream()
.map(name -> new AbstractMap.SimpleEntry<>(name, this.devDependencyProperties.getProperty(name)))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

private static IllegalArgumentException onlyOneConfig() {
return new IllegalArgumentException("must specify exactly one configFile or config");
return new IllegalArgumentException("must specify exactly one prettierVersion, devDependencies or devDependencyProperties");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,30 @@ public void unique_dependency_config() throws Exception {
MavenRunner.Result result = mavenRunner().withArguments("spotless:apply").runHasError();
assertThat(result.output()).contains("must specify exactly one configFile or config");
}

@Test
public void custom_plugin() throws Exception {
writePomWithFormatSteps(
"<includes><include>php-example.php</include></includes>",
"<prettier>",
" <devDependencyProperties>",
" <property>",
" <name>prettier</name>",
" <value>2.0.5</value>",
" </property>",
" <property>",
" <name>@prettier/plugin-php</name>",
" <value>0.14.2</value>",
" </property>",
" </devDependencyProperties>",
" <config>",
" <tabWidth>3</tabWidth>",
" <parser>php</parser>",
" </config>",
"</prettier>");

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");
}
}

0 comments on commit 8cbbb27

Please sign in to comment.