Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added formatter [`eclipse-wtp`](https://github.com/diffplug/spotless/tree/main/plugin-gradle#eclipse-web-tools-platform)

## [0.2.0] - 2025-07-31

### Fixed
Expand Down
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ or apply the formatting to the files.
Available formatting steps:
clang-format Runs clang-format
clean-that CleanThat enables automatic refactoring of Java code.
eclipse-wtp Runs Eclipse WTP formatter (4.21.0)
format-annotations Corrects line break formatting of type annotations in
java files.
google-java-format Runs google java format
Expand Down Expand Up @@ -186,6 +187,7 @@ Spotless CLI supports the following formatter steps in alphabetical order:

- [clang-format](#clang-format)
- [clean-that](#clean-that)
- [eclipse-wtp](#eclipse-wtp)
- [format-annotations](#format-annotations)
- [google-java-format](#google-java-format)
- [license-header](#license-header)
Expand Down Expand Up @@ -311,6 +313,74 @@ Example usage:
spotless --target '**/src/**/*.java' clean-that --exclude-mutator=StreamAnyMatch
```

### eclipse-wtp

<!---freshmark eclipsewtpshields
output = [
link(shield('spotless eclipse wtp version', 'spotless-eclipse-wtp', '{{libs.versions.native.include.spotlessEclipseWtp}}', 'blue'), 'https://central.sonatype.com/artifact/com.diffplug.spotless/spotless-eclipse-wtp/{{libs.versions.native.include.spotlessEclipseWtp}}'),
link(shield('eclipse wtp version', 'eclipse-wtp-formatter', '{{libs.versions.native.include.spotlessEclipseWtpFormatter}}', 'blue'), 'https://github.com/diffplug/spotless/blob/main/lib-extra/src/main/resources/com/diffplug/spotless/extra/eclipse_wtp_formatter/v{{libs.versions.native.include.spotlessEclipseWtpFormatter}}'),
].join('\n')
-->

[![spotless eclipse wtp version](https://img.shields.io/badge/spotless--eclipse--wtp-3.23.0-blue.svg)](https://central.sonatype.com/artifact/com.diffplug.spotless/spotless-eclipse-wtp/3.23.0)
[![eclipse wtp version](https://img.shields.io/badge/eclipse--wtp--formatter-4.21.0-blue.svg)](https://github.com/diffplug/spotless/blob/main/lib-extra/src/main/resources/com/diffplug/spotless/extra/eclipse_wtp_formatter/v4.21.0)

<!---freshmark /eclipsewtpshields -->

The [eclipse web tools platform (WTP)](https://projects.eclipse.org/projects/webtools) formatter is a formatter for web files such as HTML, CSS, JavaScript, JSON, XML and XHTML.

It comes with reasonable defaults but can be configured using configuration files. For details see the [spotless documentation](https://github.com/diffplug/spotless/tree/main/plugin-gradle#eclipse-web-tools-platform).

To see usage instructions for the eclipse-wtp formatter, run: `spotless eclipse-wtp --help`

<!---freshmark usage_eclipse_wtp
output =
'```\n' +
{{usage.eclipse-wtp.array}}.join('\n') +
'\n```';
-->

```
Usage: spotless eclipse-wtp [-hV] [-f]... [-t=<type>]
Runs Eclipse WTP formatter (4.21.0)
-f, --config-file The path to the Eclipse WTP configuration file. For
supported config file options see spotless
documentation (additional info links).
-h, --help Show this help message and exit.
-t, --type=<type> The type of the Eclipse WTP formatter. If not provided,
the type will be guessed based on the first few files
we find. If that does not work, we fail the formatting
run.
One of: CSS, HTML, JS, JSON, XML, XHTML
-V, --version Print version information and exit.

✅ This step supports the following file types:
* css
* html
* js
* json
* xml
* xhtml

🌎 Additional info:
* https://github.com/diffplug/spotless/tree/main/plugin-gradle#eclipse-web-to
ols-platform

* https://projects.eclipse.org/projects/webtools
```

<!---freshmark /usage_eclipse_wtp -->

Example usage:

```shell
# format all js files using (multiple) project-specific configuration files
# for details regarding the configuration files see the spotless documentation
spotless --target '**/*.js' eclipse-wtp --type js --config-file spotless.xml.prefs --config-file spotless.common.properties
# or use defaults and infer type from files
spotless --target '**/*.css' eclipse-wtp
```

### format-annotations

In Java, type annotations should be on the same line as the type that they qualify. This formatter fixes this for you.
Expand Down
18 changes: 17 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import com.diffplug.spotless.cli.picocli.usage.GenerateUsagePropertiesTask
import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep
import org.gradle.plugins.ide.eclipse.model.EclipseWtp

plugins {
id 'buildlogic.picocli-conventions'
Expand All @@ -9,6 +11,7 @@ plugins {

version = rootProject.version


dependencies {
testImplementation project(':testlib')
implementation libs.bundles.spotless.libs
Expand All @@ -17,6 +20,19 @@ dependencies {
// these are fixed versions of the otherwise dynamic dependencies for spotless
// this is necessary to allow for native compilation where reflective access to dynamic jars is not possible
implementation libs.bundles.native.includes

// Eclipse WTP formatter used a custom lockfile to ensure the formatter has the
// correct version of all its libraries
def resourceName = "/com/diffplug/spotless/extra/eclipse_wtp_formatter/v4.21.0.lockfile"
logger.debug("reading eclipse wtp resource: " + resourceName)
EclipseWtpFormatterStep.getResource(resourceName)
.readLines()
.findAll { !it.startsWith('#')} // filter out comments
.each {
implementation("${it}") {
transitive=false
}
}
}

application {
Expand All @@ -35,7 +51,7 @@ gradle.taskGraph.whenReady { TaskExecutionGraph graph ->
}

tasks.withType(Test).configureEach {
if (it.name == 'test' || it.name == 'testNpm') {
if (it.name == 'test' || it.name == 'testNpm' || it.name == 'testSeparateJvm') {
it.outputs.dir(nativeCompileMetaDir)
if (project.hasProperty('agent')) {
it.inputs.property('agent', project.property('agent')) // make sure to re-run tests if agent changes
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/diffplug/spotless/cli/SpotlessCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.diffplug.spotless.cli.logging.output.Output;
import com.diffplug.spotless.cli.steps.ClangFormat;
import com.diffplug.spotless.cli.steps.CleanThat;
import com.diffplug.spotless.cli.steps.EclipseWtp;
import com.diffplug.spotless.cli.steps.FormatAnnotations;
import com.diffplug.spotless.cli.steps.GoogleJavaFormat;
import com.diffplug.spotless.cli.steps.LicenseHeader;
Expand Down Expand Up @@ -97,6 +98,7 @@
subcommands = {
ClangFormat.class,
CleanThat.class,
EclipseWtp.class,
FormatAnnotations.class,
GoogleJavaFormat.class,
LicenseHeader.class,
Expand Down
122 changes: 122 additions & 0 deletions app/src/main/java/com/diffplug/spotless/cli/steps/EclipseWtp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2025 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.cli.steps;

import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
import java.util.function.Supplier;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.cli.core.SpotlessActionContext;
import com.diffplug.spotless.cli.core.TargetFileTypeInferer;
import com.diffplug.spotless.cli.help.AdditionalInfoLinks;
import com.diffplug.spotless.cli.help.OptionConstants;
import com.diffplug.spotless.cli.help.SupportedFileTypes;
import com.diffplug.spotless.extra.EclipseBasedStepBuilder;
import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep;

import picocli.CommandLine;

@CommandLine.Command(
name = "eclipse-wtp",
description = "Runs Eclipse WTP formatter (" + EclipseWtp.ECLIPSE_WTP_VERSION + ")")
@SupportedFileTypes({"css", "html", "js", "json", "xml", "xhtml"})
@AdditionalInfoLinks({
"https://github.com/diffplug/spotless/tree/main/plugin-gradle#eclipse-web-tools-platform",
"https://projects.eclipse.org/projects/webtools"
})
public class EclipseWtp extends SpotlessFormatterStep {

public static final String ECLIPSE_WTP_VERSION = "4.21.0"; // TODO we need to slurp in the lock file also

@CommandLine.Option(
names = {"-f", "--config-file"},
arity = "0",
description = "The path to the Eclipse WTP configuration file. "
+ "For supported config file options see spotless documentation (additional info links).")
List<Path> configFiles;

@CommandLine.Option(
names = {"-t", "--type"},
description =
"The type of the Eclipse WTP formatter. If not provided, the type will be guessed based on the first few files we find. If that does not work, we fail the formatting run."
+ OptionConstants.VALID_VALUES_SUFFIX)
Type type;

public enum Type {
CSS(EclipseWtpFormatterStep.CSS),
HTML(EclipseWtpFormatterStep.HTML),
JS(EclipseWtpFormatterStep.JS),
JSON(EclipseWtpFormatterStep.JSON),
XML(EclipseWtpFormatterStep.XML),
XHTML(EclipseWtpFormatterStep.HTML); // XHTML is treated as HTML in Eclipse WTP

private final EclipseWtpFormatterStep backendEclipseWtpType;

Type(EclipseWtpFormatterStep backendEclipseWtpType) {
this.backendEclipseWtpType = backendEclipseWtpType;
}

public @NotNull EclipseWtpFormatterStep toEclipseWtpType() {
return this.backendEclipseWtpType;
}

public static @Nullable Type fromTargetFileType(@NotNull TargetFileTypeInferer.TargetFileType targetFileType) {
return switch (targetFileType.fileExtension().toLowerCase(Locale.getDefault())) {
case "css" -> CSS;
case "html", "htm" -> HTML;
case "js" -> JS;
case "json" -> JSON;
case "xml" -> XML;
case "xhtml" -> XHTML;
default -> null;
};
}
}

@Override
public @NotNull List<FormatterStep> prepareFormatterSteps(SpotlessActionContext context) {
EclipseWtpFormatterStep wtpType = type(context::targetFileType).toEclipseWtpType();
EclipseBasedStepBuilder builder = wtpType.createBuilder(context.provisioner());
builder.setVersion(ECLIPSE_WTP_VERSION);
if (configFiles != null && !configFiles.isEmpty()) {
builder.setPreferences(configFiles.stream()
.map(context::resolvePath)
.map(Path::toFile)
.toList());
}
return List.of(builder.build());
}

private Type type(Supplier<TargetFileTypeInferer.TargetFileType> targetFileTypeSupplier) {
if (type != null) {
return type;
}
// try type inferring
TargetFileTypeInferer.TargetFileType targetFileType = targetFileTypeSupplier.get();
Type inferredType = Type.fromTargetFileType(targetFileType);
if (inferredType != null) {
return inferredType;
} else {
throw new IllegalArgumentException("Could not infer Eclipse WTP type from target file type: "
+ targetFileType.fileExtension() + " - workaround by specifying the --type option.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2025 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.cli.steps;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;

import com.diffplug.spotless.tag.CliNativeTest;
import com.diffplug.spotless.tag.CliProcessTest;
import com.diffplug.spotless.tag.SeparateJvmTest;

@Isolated
@SeparateJvmTest
@CliNativeTest
@CliProcessTest
public class EclipseWtpCssTest extends EclipseWtpTestBase {

@Test
void itSupportsFormattingCssFileType() {
String fileName = runEclipseWtpWithType(EclipseWtp.Type.CSS, "body {\n" + "a: v; b: \n" + "v;\n" + "} \n");
selfie().expectResource(fileName).toMatchDisk();
}

@Test
void itInfersCssFileTypeFromFileExtension() {
String fileName = runEclipseWtpWithTypeInferred("css", "body {\n" + "a: v; b: \n" + "v;\n" + "} \n");
selfie().expectResource(fileName).toMatchDisk();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2025 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.cli.steps;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;

import com.diffplug.spotless.tag.CliNativeTest;
import com.diffplug.spotless.tag.CliProcessTest;
import com.diffplug.spotless.tag.SeparateJvmTest;

@Isolated
@SeparateJvmTest
@CliNativeTest
@CliProcessTest
public class EclipseWtpCssWithConfigTest extends EclipseWtpTestBase {

@Test
void itUsesConfigurationFile() {
String fileName = runEclipseWtpWithTypeAndConfigFile(
EclipseWtp.Type.CSS,
"body {\n" + "a: v; b: \n" + "v;\n" + "} \n",
"org.eclipse.wst.css.core.prefs");
selfie().expectResource(fileName).toMatchDisk();
}
}
Loading
Loading