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

Added support for custom JSR-223 based formatters #945

Merged
merged 1 commit into from
Sep 27, 2021
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
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This document is intended for Spotless developers.
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Added
* Added support for custom JSR223 formatters ([#945](https://github.com/diffplug/spotless/pull/945))

## [2.17.0] - 2021-09-27
### Added
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ output = [
'| Fast format on fresh checkout using buildcache | {{yes}} | {{no}} | {{no}} | {{no}} |',
lib('generic.EndWithNewlineStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
lib('generic.IndentStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
lib('generic.Jsr223Step') +'{{no}} | {{yes}} | {{no}} | {{no}} |',
lib('generic.LicenseHeaderStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
lib('generic.NativeCmdStep') +'{{no}} | {{yes}} | {{no}} | {{no}} |',
lib('generic.ReplaceRegexStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
Expand Down Expand Up @@ -83,6 +84,7 @@ extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}}
| Fast format on fresh checkout using buildcache | :+1: | :white_large_square: | :white_large_square: | :white_large_square: |
| [`generic.EndWithNewlineStep`](lib/src/main/java/com/diffplug/spotless/generic/EndWithNewlineStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
| [`generic.IndentStep`](lib/src/main/java/com/diffplug/spotless/generic/IndentStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
| [`generic.Jsr223Step`](lib/src/main/java/com/diffplug/spotless/generic/Jsr223Step.java) | :white_large_square: | :+1: | :white_large_square: | :white_large_square: |
| [`generic.LicenseHeaderStep`](lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
| [`generic.NativeCmdStep`](lib/src/main/java/com/diffplug/spotless/generic/NativeCmdStep.java) | :white_large_square: | :+1: | :white_large_square: | :white_large_square: |
| [`generic.ReplaceRegexStep`](lib/src/main/java/com/diffplug/spotless/generic/ReplaceRegexStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
Expand Down
77 changes: 77 additions & 0 deletions lib/src/main/java/com/diffplug/spotless/generic/Jsr223Step.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2021 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.generic;

import java.io.Serializable;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.JarState;
import com.diffplug.spotless.Provisioner;

public final class Jsr223Step {
// prevent direct instantiation
private Jsr223Step() {}

public static FormatterStep create(String name, String dependency, CharSequence engine, CharSequence script, Provisioner provisioner) {
Objects.requireNonNull(name, "name");
Objects.requireNonNull(engine, "engine");
Objects.requireNonNull(script, "script");
return FormatterStep.createLazy(name,
() -> new State(dependency == null ? null : JarState.from(dependency, provisioner), engine, script),
State::toFormatter);
}

private static final class State implements Serializable {
private static final long serialVersionUID = 1L;

private final JarState jarState;
private final String engine;
private final String script;

State(JarState jarState, CharSequence engine, CharSequence script) {
this.jarState = jarState;
this.engine = engine.toString();
this.script = script.toString();
}

FormatterFunc toFormatter() {
ScriptEngineManager scriptEngineManager;
if (jarState == null) {
scriptEngineManager = new ScriptEngineManager(ClassLoader.getSystemClassLoader());
} else {
scriptEngineManager = new ScriptEngineManager(jarState.getClassLoader());
}
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(engine);

if (scriptEngine == null) {
throw new IllegalArgumentException("Unknown script engine '" + engine + "'. Available engines: " +
scriptEngineManager.getEngineFactories().stream().flatMap(f -> f.getNames().stream()).collect(Collectors.joining(", ")));
}

// evaluate script code
return raw -> {
scriptEngine.put("source", raw);
return (String) scriptEngine.eval(script);
};
}
}
}
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]
### Added
* Added support for custom JSR223 formatters ([#945](https://github.com/diffplug/spotless/pull/945))

## [2.14.0] - 2021-09-27
### Added
Expand Down
7 changes: 7 additions & 0 deletions plugin-maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,13 @@ to true.
<spacesPerTab>4</spacesPerTab> <!-- optional, default is 4 -->
</indent>

<jsr223> <!-- specify replacements using JSR223 scripting -->
<name>Greetings to Mars</name>
<dependency>org.codehaus.groovy:groovy-jsr223:3.0.9</dependency> <!-- optional, maven dependency, containing the jsr223 compatible scripting engine-->
<engine>groovy</engine> <!-- nashorn is provided by JDK 8-14, other engines can be loaded from the given dependency -->
<script>source.replace('World','Mars');</script> <!-- the source variable contains the unformatted code, the returned value of the script is the formatted code -->
</jsr223>

<nativeCmd> <!-- run a native binary -->
<name>Greetings to Mars from sed</name>
<pathToExe>/usr/bin/sed</pathToExe> <!-- path to the binary, unformatted code is send via StdIn, formatted code is expected on StdOut -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ public final void addIndent(Indent indent) {
addStepFactory(indent);
}

public final void addJsr223(Jsr223 jsr223) {
addStepFactory(jsr223);
}

public final void addTrimTrailingWhitespace(TrimTrailingWhitespace trimTrailingWhitespace) {
addStepFactory(trimTrailingWhitespace);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2021 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 org.apache.maven.plugins.annotations.Parameter;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.generic.Jsr223Step;
import com.diffplug.spotless.maven.FormatterStepConfig;
import com.diffplug.spotless.maven.FormatterStepFactory;

public class Jsr223 implements FormatterStepFactory {

@Parameter
private String name;

@Parameter
private String dependency;

@Parameter
private String engine;

@Parameter
private String script;

@Override
public FormatterStep newFormatterStep(FormatterStepConfig config) {
if (name == null || engine == null || script == null) {
throw new IllegalArgumentException("Must specify 'name', 'engine' and 'script'.");
}

return Jsr223Step.create(name, dependency, engine, script, config.getProvisioner());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2021 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 static org.assertj.core.api.Assumptions.assumeThat;

import javax.script.ScriptEngineManager;

import org.junit.jupiter.api.Test;

import com.diffplug.spotless.maven.MavenIntegrationHarness;

public class Jsr223Test extends MavenIntegrationHarness {

@Test
public void buildInNashorn() throws Exception {
// This will only work for JDKs that bundle nashorn (8-14)
assumeThat(new ScriptEngineManager().getEngineByName("nashorn")).isNotNull();
writePomWithFormatSteps(
"<jsr223>",
" <name>Greetings to Mars</name>",
" <engine>nashorn</engine>",
" <script>source.replace('World','Mars');</script>",
"</jsr223>");
runTest("Hello World", "Hello Mars");
}

@Test
public void groovyFromJarState() throws Exception {
writePomWithFormatSteps(
"<jsr223>",
" <name>Greetings to Mars</name>",
" <dependency>org.codehaus.groovy:groovy-jsr223:3.0.9</dependency>",
" <engine>groovy</engine>",
" <script>source.replace('World','Mars')</script>",
"</jsr223>");
runTest("Hello World", "Hello Mars");
}

private void runTest(String sourceContent, String targetContent) throws Exception {
String path = "src/main/java/test.java";
setFile(path).toContent(sourceContent);
mavenRunner().withArguments("spotless:apply").runNoError();
assertFile(path).hasContent(targetContent);
}
}