Skip to content

Feature/use native npm #606

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

Merged
merged 43 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
cf00d4d
poc: call native node-server from within java
simschla Jun 3, 2020
b07af27
resolve prettier config once only
simschla Jun 5, 2020
2180d35
extract http/url handling part into a pretty simple client...
simschla Jun 5, 2020
3c8d2ca
raw state: start node server and execute rest calls to it
simschla Jun 6, 2020
372107a
use native node approach for tsfmt
simschla Jun 7, 2020
51da6fe
remove dependency to j2v8
simschla Jun 7, 2020
9999bdd
spotlessApply
simschla Jun 7, 2020
03fbd98
add more details in case npm autodiscovery fails
simschla Jun 7, 2020
8f88dc2
remove j2v8 reference from readme
simschla Jun 7, 2020
589940c
cleanup server startup code
simschla Jun 7, 2020
48ce207
extract file handling to helper class
simschla Jun 7, 2020
3dcb1ec
refactor and use npmProcess helper instance
simschla Jun 7, 2020
78a0ea8
reduce log noise from npm install call
simschla Jun 7, 2020
bc3c86a
only listen on localhost
simschla Jun 7, 2020
57f97b9
cleanup logging
simschla Jun 7, 2020
d7f3564
enable spotless for js formatting
simschla Jun 7, 2020
ee2dd1d
format js files using spotless
simschla Jun 7, 2020
fbb3961
refactoring: extract inner classes and renamings
simschla Jun 7, 2020
eafb850
adapt changelog
simschla Jun 7, 2020
d47a949
adapt to newer copyright header
simschla Jun 7, 2020
674044b
try to fix circle-ci (use node for running internal spotlessJavascript)
simschla Jun 7, 2020
c70bc85
Remove javascript from our dogfooding.
nedtwigg Jun 8, 2020
12680c5
Fix spotbugs warning.
nedtwigg Jun 8, 2020
92197e1
Windows cache seems to be broken, we'll just let it be slow.
nedtwigg Jun 8, 2020
c0879e1
fixing ci build
simschla Jun 8, 2020
0d6bd65
fixing ci build
simschla Jun 9, 2020
7c91e93
Revert "fixing ci build"
simschla Jun 9, 2020
a3c5614
cleanup accidential sysout checkin
simschla Jun 9, 2020
42309c7
Make the windows build run the npmTest
nedtwigg Jun 11, 2020
f5e7e6c
Oops, windows build doesn't want './'
nedtwigg Jun 11, 2020
d319266
Oops, we need to store the test results too!
nedtwigg Jun 11, 2020
5764f4c
Add a test that recreates the problem I'm seeing.
nedtwigg Jun 11, 2020
a12343f
bump version numbers to latest
simschla Jun 10, 2020
2bc0464
improve robustness and error feedback
simschla Jun 11, 2020
6f8c550
adding a test to prove that we can support prettier-plugins now
simschla Jun 11, 2020
0808fc2
documenting the community-plugin benefit and adding more examples
simschla Jun 11, 2020
e2981e5
PR feedback: try to avoid `**/*.filetype` as target examples
simschla Jun 12, 2020
8eff924
PR feedback: add links to prettier plugins
simschla Jun 12, 2020
dd6f120
add support for prettier-plugins to maven-builds and document in README
simschla Jun 12, 2020
bc9410b
adapting test for new output format
simschla Jun 12, 2020
38053bc
and verify what we actually learned: error message needs to be relaye…
simschla Jun 12, 2020
08d8321
Update changes.
nedtwigg Jun 12, 2020
a69670e
Remove some empty newlines.
nedtwigg Jun 12, 2020
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
Prev Previous commit
Next Next commit
refactoring: extract inner classes and renamings
and improve http resource handling
  • Loading branch information
simschla committed Jun 7, 2020
commit fbb3961fb1b13b02a3b35666324de38d66bd0fca
110 changes: 110 additions & 0 deletions lib/src/main/java/com/diffplug/spotless/npm/JsonEscaper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* 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.npm;

import static java.util.Objects.requireNonNull;

/**
* Simple implementation on how to escape values when printing json.
* Implementation is partly based on https://github.com/stleary/JSON-java
*/
final class JsonEscaper {
private JsonEscaper() {
// no instance
}

public static String jsonEscape(Object val) {
requireNonNull(val);
if (val instanceof JsonRawValue) {
return jsonEscape((JsonRawValue) val);
}
if (val instanceof String) {
return jsonEscape((String) val);
}
return val.toString();
}

private static String jsonEscape(JsonRawValue jsonRawValue) {
return jsonRawValue.getRawJson();
}

private static String jsonEscape(String unescaped) {
/**
* the following characters are reserved in JSON and must be properly escaped to be used in strings:
*
* Backspace is replaced with \b
* Form feed is replaced with \f
* Newline is replaced with \n
* Carriage return is replaced with \r
* Tab is replaced with \t
* Double quote is replaced with \"
* Backslash is replaced with \\
*
* additionally we handle xhtml '</bla>' string
* and non-ascii chars
*/
StringBuilder escaped = new StringBuilder();
escaped.append('"');
char b;
char c = 0;
for (int i = 0; i < unescaped.length(); i++) {
b = c;
c = unescaped.charAt(i);
switch (c) {
case '\"':
escaped.append('\\').append('"');
break;
case '\n':
escaped.append('\\').append('n');
break;
case '\r':
escaped.append('\\').append('r');
break;
case '\t':
escaped.append('\\').append('t');
break;
case '\b':
escaped.append('\\').append('b');
break;
case '\f':
escaped.append('\\').append('f');
break;
case '\\':
escaped.append('\\').append('\\');
break;
case '/':
if (b == '<') {
escaped.append('\\');
}
escaped.append(c);
break;
default:
if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
|| (c >= '\u2000' && c < '\u2100')) {
escaped.append('\\').append('u');
String hexString = Integer.toHexString(c);
escaped.append("0000", 0, 4 - hexString.length());
escaped.append(hexString);
} else {
escaped.append(c);
}
}
}
escaped.append('"');
return escaped.toString();
}

}
37 changes: 37 additions & 0 deletions lib/src/main/java/com/diffplug/spotless/npm/JsonRawValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.npm;

import static java.util.Objects.requireNonNull;

/**
* Wrapper class to signal the contained string must not be escaped when printing to json.
*/
class JsonRawValue {
private final String rawJson;

private JsonRawValue(String rawJson) {
this.rawJson = requireNonNull(rawJson);
}

static JsonRawValue wrap(String rawJson) {
return new JsonRawValue(rawJson);
}

public String getRawJson() {
return rawJson;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ protected NpmFormatterStepStateBase(String stepName, NpmConfig npmConfig, File b

private File prepareNodeServer(File buildDir) throws IOException {
File targetDir = new File(buildDir, "spotless-node-modules-" + stepName);
SimpleResourceHelper.assertDirectoryExists(targetDir);
SimpleResourceHelper.writeUtf8StringToFile(targetDir, "package.json", this.npmConfig.getPackageJsonContent());
SimpleResourceHelper.writeUtf8StringToFile(targetDir, "serve.js", this.npmConfig.getServeScriptContent());
NpmResourceHelper.assertDirectoryExists(targetDir);
NpmResourceHelper.writeUtf8StringToFile(targetDir, "package.json", this.npmConfig.getPackageJsonContent());
NpmResourceHelper.writeUtf8StringToFile(targetDir, "serve.js", this.npmConfig.getServeScriptContent());
runNpmInstall(targetDir);
return targetDir;
}
Expand All @@ -78,13 +78,13 @@ protected ServerProcessInfo npmRunServer() throws ServerStartException {
// The npm process will output the randomly selected port of the http server process to 'server.port' file
// so in order to be safe, remove such a file if it exists before starting.
final File serverPortFile = new File(this.nodeModulesDir, "server.port");
SimpleResourceHelper.deleteFileIfExists(serverPortFile);
NpmResourceHelper.deleteFileIfExists(serverPortFile);
// start the http server in node
Process server = new NpmProcess(this.nodeModulesDir, this.npmExecutable).start();

// await the readiness of the http server - wait for at most 60 seconds
try {
SimpleResourceHelper.awaitReadableFile(serverPortFile, Duration.ofSeconds(60));
NpmResourceHelper.awaitReadableFile(serverPortFile, Duration.ofSeconds(60));
} catch (TimeoutException timeoutException) {
// forcibly end the server process
try {
Expand All @@ -98,7 +98,7 @@ protected ServerProcessInfo npmRunServer() throws ServerStartException {
throw timeoutException;
}
// read the server.port file for resulting port and remember the port for later formatting calls
String serverPort = SimpleResourceHelper.readUtf8StringFromFile(serverPortFile).trim();
String serverPort = NpmResourceHelper.readUtf8StringFromFile(serverPortFile).trim();
return new ServerProcessInfo(server, serverPort, serverPortFile);
} catch (IOException | TimeoutException e) {
throw new ServerStartException(e);
Expand Down Expand Up @@ -155,7 +155,7 @@ public String getBaseUrl() {

@Override
public void close() throws Exception {
SimpleResourceHelper.deleteFileIfExists(serverPortFile);
NpmResourceHelper.deleteFileIfExists(serverPortFile);
if (this.server.isAlive()) {
this.server.destroy();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,27 @@
*/
package com.diffplug.spotless.npm;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.Duration;
import java.util.concurrent.TimeoutException;

import com.diffplug.spotless.ThrowingEx;

final class SimpleResourceHelper {
private SimpleResourceHelper() {
final class NpmResourceHelper {
private NpmResourceHelper() {
// no instance required
}

static void writeUtf8StringToFile(File targetDir, String fileName, String packageJsonContent) throws IOException {
static void writeUtf8StringToFile(File targetDir, String fileName, String stringToWrite) throws IOException {
File packageJsonFile = new File(targetDir, fileName);
Files.write(packageJsonFile.toPath(), packageJsonContent.getBytes(StandardCharsets.UTF_8));
Files.write(packageJsonFile.toPath(), stringToWrite.getBytes(StandardCharsets.UTF_8));
}

static void writeUtf8StringToOutputStream(String stringToWrite, OutputStream outputStream) throws IOException {
final byte[] bytes = stringToWrite.getBytes(StandardCharsets.UTF_8);
outputStream.write(bytes);
}

static void deleteFileIfExists(File file) throws IOException {
Expand All @@ -45,14 +47,8 @@ static void deleteFileIfExists(File file) throws IOException {
}

static String readUtf8StringFromClasspath(Class<?> clazz, String resourceName) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (InputStream input = clazz.getResourceAsStream(resourceName)) {
byte[] buffer = new byte[1024];
int numRead;
while ((numRead = input.read(buffer)) != -1) {
output.write(buffer, 0, numRead);
}
return output.toString(StandardCharsets.UTF_8.name());
return readUtf8StringFromInputStream(input);
} catch (IOException e) {
throw ThrowingEx.asRuntime(e);
}
Expand All @@ -66,6 +62,20 @@ static String readUtf8StringFromFile(File file) {
}
}

static String readUtf8StringFromInputStream(InputStream input) {
try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int numRead;
while ((numRead = input.read(buffer)) != -1) {
output.write(buffer, 0, numRead);
}
return output.toString(StandardCharsets.UTF_8.name());
} catch (IOException e) {
throw ThrowingEx.asRuntime(e);
}
}

static void assertDirectoryExists(File directory) throws IOException {
if (!directory.exists()) {
if (!directory.mkdirs()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ public static class State extends NpmFormatterStepStateBase implements Serializa
super(stepName,
new NpmConfig(
replaceDevDependencies(
SimpleResourceHelper.readUtf8StringFromClasspath(PrettierFormatterStep.class, "/com/diffplug/spotless/npm/prettier-package.json"),
NpmResourceHelper.readUtf8StringFromClasspath(PrettierFormatterStep.class, "/com/diffplug/spotless/npm/prettier-package.json"),
new TreeMap<>(devDependencies)),
"prettier",
SimpleResourceHelper.readUtf8StringFromClasspath(PrettierFormatterStep.class, "/com/diffplug/spotless/npm/prettier-serve.js")),
NpmResourceHelper.readUtf8StringFromClasspath(PrettierFormatterStep.class, "/com/diffplug/spotless/npm/prettier-serve.js")),
buildDir,
npm);
this.prettierConfig = requireNonNull(prettierConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
import java.util.LinkedHashMap;
import java.util.Map;

import com.diffplug.spotless.npm.SimpleJsonWriter.RawJsonValue;

public class PrettierRestService {

private final SimpleRestClient restClient;
Expand All @@ -35,7 +33,7 @@ public String resolveConfig(File prettierConfigPath, Map<String, Object> prettie
jsonProperties.put("prettier_config_path", prettierConfigPath.getAbsolutePath());
}
if (prettierConfigOptions != null) {
jsonProperties.put("prettier_config_options", SimpleJsonWriter.of(prettierConfigOptions).toRawJsonValue());
jsonProperties.put("prettier_config_options", SimpleJsonWriter.of(prettierConfigOptions).toJsonRawValue());

}
return restClient.postJson("/prettier/config-options", jsonProperties);
Expand All @@ -45,7 +43,7 @@ public String format(String fileContent, String configOptionsJsonString) {
Map<String, Object> jsonProperties = new LinkedHashMap<>();
jsonProperties.put("file_content", fileContent);
if (configOptionsJsonString != null) {
jsonProperties.put("config_options", RawJsonValue.wrap(configOptionsJsonString));
jsonProperties.put("config_options", JsonRawValue.wrap(configOptionsJsonString));
}

return restClient.postJson("/prettier/format", jsonProperties);
Expand Down
Loading