Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Prettier to Maven plugin #555

Merged
merged 14 commits into from
Apr 10, 2020
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ lib('java.RemoveUnusedImportsStep') +'{{yes}} | {{yes}}
extra('java.EclipseFormatterStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('kotlin.KtLintStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('markdown.FreshMarkStep') +'{{yes}} | {{no}} | {{no}} |',
lib('npm.PrettierFormatterStep') +'{{yes}} | {{no}} | {{no}} |',
lib('npm.PrettierFormatterStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('npm.TsFmtFormatterStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('scala.ScalaFmtStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('sql.DBeaverSQLFormatterStep') +'{{yes}} | {{no}} | {{no}} |',
Expand All @@ -73,7 +73,7 @@ extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}}
| [`java.EclipseFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseFormatterStep.java) | :+1: | :+1: | :white_large_square: |
| [`kotlin.KtLintStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java) | :+1: | :+1: | :white_large_square: |
| [`markdown.FreshMarkStep`](lib/src/main/java/com/diffplug/spotless/markdown/FreshMarkStep.java) | :+1: | :white_large_square: | :white_large_square: |
| [`npm.PrettierFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java) | :+1: | :white_large_square: | :white_large_square: |
| [`npm.PrettierFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java) | :+1: | :+1: | :white_large_square: |
| [`npm.TsFmtFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java) | :+1: | :+1: | :white_large_square: |
| [`scala.ScalaFmtStep`](lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java) | :+1: | :+1: | :white_large_square: |
| [`sql.DBeaverSQLFormatterStep`](lib/src/main/java/com/diffplug/spotless/sql/DBeaverSQLFormatterStep.java) | :+1: | :white_large_square: | :white_large_square: |
Expand Down
2 changes: 2 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
###
* Support for prettier ([#555](https://github.com/diffplug/spotless/pull/555)).

## [1.29.0] - 2020-04-02
### Added
Expand Down
67 changes: 66 additions & 1 deletion plugin-maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ Spotless supports the following powerful formatters:
* Eclipse's [CDT](https://www.eclipse.org/cdt/) C/C++ code formatter
* Eclipse's [WTP](https://www.eclipse.org/webtools/) Web-Tools code formatters
* Google's [google-java-format](https://github.com/google/google-java-format)
* [Typescript Tsfmt formatter](https://github.com/vvakame/typescript-formatter)
* [Prettier formatter](https://prettier.io)
* User-defined license enforcement, regex replacement, etc.

Contributions are welcome, see [the contributing guide](../CONTRIBUTING.md) for development info.
Expand Down Expand Up @@ -200,11 +202,13 @@ Use the Eclipse to define the *Code Style preferences* (see [Eclipse documentati
```xml
<configuration>
<typescript>
<tsfmt>

<!-- optionally define which files will be formatted. -->
<includes>
<include>src/**/*.ts</include> <!-- default value if nothing is specified -->
</includes>

<tsfmt>
source-knights marked this conversation as resolved.
Show resolved Hide resolved
<!-- must specify exactly one of the following "{foo}File" or "config" elements -->
<tslintFile>${basedir}/path/to/repo/tslint.json</tslintFile>
<tsfmtFile>${basedir}/path/to/repo/tsfmt.json</tsfmtFile>
Expand Down Expand Up @@ -243,6 +247,67 @@ 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 tsfmt using [J2V8](https://github.com/eclipsesource/J2V8) internally after that.

<a name="prettier"></a>

## Applying [Prettier](https://prettier.io) to javascript | flow | typeScript | css | scss | less | jsx | graphQL | yaml | etc.

Prettier is a formatter that can format [multiple file types](https://prettier.io/docs/en/language-support.html).

To use prettier, you first have to specify the files that you want it to apply to. Then you specify prettier, and how you want to apply it.

```xml
<configuration>
<formats>

<format>
<includes>
<include>src/**/typescript/**/*.ts</include>
</includes>

<prettier>
<!-- Specify either simple prettier version (1.19.0 is max supported,
which is also default) or whole devDependencies -->
source-knights marked this conversation as resolved.
Show resolved Hide resolved
<prettierVersion>1.19.0</prettierVersion>
<devDependencies>
<prettier>1.19.0</prettier>
</devDependencies>

<!-- Specify config file and/or inline config -->
<configFile>${basedir}/path/to/configfile</configFile>
<config>
<useTabs>true</useTabs>
</config>
</prettier>
</format>

</formats>
</configuration>
```

Supported config options are documented on [prettier.io](https://prettier.io/docs/en/options.html).
Supported config file variants are documented on [prettier.io](https://prettier.io/docs/en/configuration.html).

*Please note:*
- The auto-discovery of config files (up the file tree) will not work when using prettier within spotless.
- Prettier's override syntax is not supported when using prettier within spotless.

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

### 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.
Spotless will try to auto-discover an npm installation. If that is not working for you, it is possible to directly configure the npm binary to use.

```xml
<formats><format><prettier>
<npmExecutable>/usr/bin/npm</npmExecutable>
source-knights marked this conversation as resolved.
Show resolved Hide resolved
...
```

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.

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

## Applying to custom sources
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ public final void addEclipseWtp(EclipseWtp eclipseWtp) {
addStepFactory(eclipseWtp);
}

public final void addPrettier(Prettier prettier) {
addStepFactory(prettier);
}

protected final void addStepFactory(FormatterStepFactory stepFactory) {
Objects.requireNonNull(stepFactory);
stepFactories.add(stepFactory);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright 2016 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.maven.generic;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;

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

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.maven.FormatterStepConfig;
import com.diffplug.spotless.maven.FormatterStepFactory;
import com.diffplug.spotless.npm.PrettierConfig;
import com.diffplug.spotless.npm.PrettierFormatterStep;

public class Prettier implements FormatterStepFactory {

@Parameter
private String prettierVersion;

@Parameter
private Map<String, String> devDependencies;

@Parameter
private Map<String, String> config;

@Parameter
private String configFile;

@Parameter
private String npmExecutable;

@Override
public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {

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

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

File npm = npmExecutable != null ? stepConfig.getFileLocator().locateLocal(npmExecutable) : null;

// process config file or inline config
File configFileHandler;
if (this.configFile != null) {
configFileHandler = stepConfig.getFileLocator().locateLocal(this.configFile);
} else {
configFileHandler = null;
}
source-knights marked this conversation as resolved.
Show resolved Hide resolved

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());
}
}
}
} else {
configInline = null;
}

// create the format step
PrettierConfig prettierConfig = new PrettierConfig(configFileHandler, configInline);
File buildDir = stepConfig.getFileLocator().getBuildDir();
return PrettierFormatterStep.create(devDependencies, stepConfig.getProvisioner(), buildDir, npm, prettierConfig);
}

private static IllegalArgumentException onlyOneConfig() {
return new IllegalArgumentException("must specify exactly one configFile or config");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ protected void writePomWithTypescriptSteps(String... steps) throws IOException {
writePom(groupWithSteps("typescript", steps));
}

protected void writePomWithPrettierSteps(String includes, String... steps) throws IOException {
writePom(formats(groupWithSteps("format", including(includes), steps)));
}

protected void writePom(String... configuration) throws IOException {
writePom(null, configuration);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2016 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.maven.prettier;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;

import org.junit.Test;

import com.diffplug.spotless.maven.MavenIntegrationTest;
import com.diffplug.spotless.maven.MavenRunner;

public class PrettierFormatStepTest extends MavenIntegrationTest {

private void run(String kind, String suffix) throws IOException, InterruptedException {
String configPath = ".prettierrc.yml";
setFile(configPath).toResource("npm/prettier/filetypes/" + kind + "/" + ".prettierrc.yml");
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
public void prettier_typescript() throws Exception {
String suffix = "ts";
writePomWithPrettierSteps("**/*." + suffix,
"<prettier>",
" <prettierVersion>1.16.4</prettierVersion>",
" <configFile>.prettierrc.yml</configFile>",
"</prettier>");
run("typescript", suffix);
}

@Test
public void prettier_html() throws Exception {
String suffix = "html";
writePomWithPrettierSteps("**/*." + suffix,
"<prettier>",
" <prettierVersion>1.16.4</prettierVersion>",
" <configFile>.prettierrc.yml</configFile>",
"</prettier>");
run("html", suffix);
}

@Test
public void prettier_tsx() throws Exception {
String suffix = "tsx";
writePomWithPrettierSteps("src/main/**/*." + suffix,
"<includes><include>src/**/*.tsx</include></includes>",
"<prettier>",
" <prettierVersion>1.16.4</prettierVersion>",
" <configFile>.prettierrc.yml</configFile>",
"</prettier>");
run("tsx", suffix);
}

@Test
public void prettier_tsx_inline_config() throws Exception {
String suffix = "tsx";
writePomWithPrettierSteps("src/main/**/*." + suffix,
"<prettier>",
" <prettierVersion>1.16.4</prettierVersion>",
" <config><parser>typescript</parser></config>",
"</prettier>");
run("tsx", suffix);
}

@Test
public void unique_dependency_config() throws Exception {
writePomWithFormatSteps(
"<includes><include>**/*.ts</include></includes>",
"<prettier>",
" <prettierVersion>1.16.4</prettierVersion>",
" <devDependencies><prettier>1.16.4</prettier></devDependencies>",
"</prettier>");

MavenRunner.Result result = mavenRunner().withArguments("spotless:apply").runHasError();
assertThat(result.output()).contains("must specify exactly one configFile or config");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
parser: html
13 changes: 13 additions & 0 deletions testlib/src/main/resources/npm/prettier/filetypes/html/html.clean
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="viewport" content="with=device-width" />
<title>Test</title>
<script type="module" src="module.js"></script>
<script type="module2" src="module2.js"></script>

<link rel="stylesheet" type="text/css" href="style.css" />
</head>

<body></body>
</html>
17 changes: 17 additions & 0 deletions testlib/src/main/resources/npm/prettier/filetypes/html/html.dirty
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html dir="ltr" lang="en">

<head>
<meta
charset="viewport"
content="with=device-width">
<title>Test</title><script type="module" src="module.js"></script>
<script type="module2" src="module2.js"></script>

<link rel="stylesheet" type ="text/css" href="style.css">
</head>

<body>

</body></html>

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
parser: typescript
files: "scr/**/*.tsx"
excludeFiles: "target/**"
Loading