Skip to content

Commit 0206246

Browse files
committed
eslint: adding tests for js
1 parent 4efc19b commit 0206246

File tree

5 files changed

+312
-6
lines changed

5 files changed

+312
-6
lines changed

lib/src/main/java/com/diffplug/spotless/npm/EslintConfig.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,11 @@ public File getEslintConfigPath() {
6262
public String getEslintConfigJs() {
6363
return eslintConfigJs;
6464
}
65+
66+
public EslintConfig verify() {
67+
if (eslintConfigPath == null && eslintConfigJs == null) {
68+
throw new IllegalArgumentException("ESLint must be configured using either a configFile or a configJs - but both are null.");
69+
}
70+
return this;
71+
}
6572
}

lib/src/main/java/com/diffplug/spotless/npm/EslintFormatterStep.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,14 @@ private static class State extends NpmFormatterStepStateBase implements Serializ
183183

184184
private EslintConfig localCopyFiles(EslintConfig orig) {
185185
if (orig.getEslintConfigPath() == null) {
186-
return orig;
186+
return orig.verify();
187187
}
188188
// If any config files are provided, we need to make sure they are at the same location as the node modules
189189
// as eslint will try to resolve plugin/config names relatively to the config file location and some
190190
// eslint configs contain relative paths to additional config files (such as tsconfig.json e.g.)
191191
FormattedPrinter.SYSOUT.print("Copying config file <%s> to <%s> and using the copy", orig.getEslintConfigPath(), nodeModulesDir);
192192
File configFileCopy = NpmResourceHelper.copyFileToDir(orig.getEslintConfigPath(), nodeModulesDir);
193-
return orig.withEslintConfigPath(configFileCopy);
193+
return orig.withEslintConfigPath(configFileCopy).verify();
194194
}
195195

196196
@Override

plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavascriptExtension.java

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static java.util.Objects.requireNonNull;
1919

2020
import java.util.Arrays;
21+
import java.util.Collections;
2122
import java.util.LinkedHashMap;
2223
import java.util.Map;
2324
import java.util.function.Consumer;
@@ -28,11 +29,13 @@
2829

2930
import org.gradle.api.Project;
3031

32+
import com.diffplug.common.collect.ImmutableList;
3133
import com.diffplug.spotless.FormatterStep;
3234
import com.diffplug.spotless.npm.EslintConfig;
3335
import com.diffplug.spotless.npm.EslintFormatterStep;
3436
import com.diffplug.spotless.npm.EslintFormatterStep.PopularStyleGuide;
3537
import com.diffplug.spotless.npm.NpmPathResolver;
38+
import com.diffplug.spotless.npm.PrettierFormatterStep;
3639

3740
public class JavascriptExtension extends FormatExtension {
3841

@@ -57,8 +60,6 @@ public JavascriptEslintConfig eslint(Map<String, String> devDependencies) {
5760
return eslint;
5861
}
5962

60-
// TODO: make the configs static so that they do not need to have a hierarchy symmetric to the extensions
61-
6263
public static abstract class EslintBaseConfig<T extends EslintBaseConfig<?>> extends NpmStepConfig<EslintBaseConfig<T>> {
6364
Map<String, String> devDependencies = new LinkedHashMap<>();
6465

@@ -146,6 +147,62 @@ protected EslintConfig eslintConfig() {
146147
}
147148
}
148149

150+
/** Uses the default version of prettier. */
151+
@Override
152+
public PrettierConfig prettier() {
153+
return prettier(PrettierFormatterStep.defaultDevDependencies());
154+
}
155+
156+
/** Uses the specified version of prettier. */
157+
@Override
158+
public PrettierConfig prettier(String version) {
159+
return prettier(PrettierFormatterStep.defaultDevDependenciesWithPrettier(version));
160+
}
161+
162+
/** Uses exactly the npm packages specified in the map. */
163+
@Override
164+
public PrettierConfig prettier(Map<String, String> devDependencies) {
165+
PrettierConfig prettierConfig = new JavascriptPrettierConfig(devDependencies);
166+
addStep(prettierConfig.createStep());
167+
return prettierConfig;
168+
}
169+
170+
private static final String DEFAULT_PRETTIER_JS_PARSER = "babel";
171+
private static final ImmutableList<String> PRETTIER_JS_PARSERS = ImmutableList.of(DEFAULT_PRETTIER_JS_PARSER, "babel-flow", "flow");
172+
173+
/**
174+
* Overrides the parser to be set to a js parser.
175+
*/
176+
public class JavascriptPrettierConfig extends PrettierConfig {
177+
178+
JavascriptPrettierConfig(Map<String, String> devDependencies) {
179+
super(devDependencies);
180+
}
181+
182+
@Override
183+
protected FormatterStep createStep() {
184+
fixParserToJavascript();
185+
return super.createStep();
186+
}
187+
188+
private void fixParserToJavascript() {
189+
if (this.prettierConfig == null) {
190+
this.prettierConfig = Collections.singletonMap("parser", DEFAULT_PRETTIER_JS_PARSER);
191+
} else {
192+
final Object currentParser = this.prettierConfig.get("parser");
193+
if (PRETTIER_JS_PARSERS.contains(String.valueOf(currentParser))) {
194+
getProject().getLogger().debug("Already javascript parser set, not overriding.");
195+
} else {
196+
this.prettierConfig.put("parser", DEFAULT_PRETTIER_JS_PARSER);
197+
if (currentParser != null) {
198+
getProject().getLogger().warn("Overriding parser option to '{}'. (Was set to '{}'.) Set it to another js parser if you have problems with '{}'.", DEFAULT_PRETTIER_JS_PARSER, currentParser, DEFAULT_PRETTIER_JS_PARSER);
199+
}
200+
}
201+
202+
}
203+
}
204+
}
205+
149206
@Override
150207
protected void setupTask(SpotlessTask task) {
151208
if (target == null) {
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
* Copyright 2016-2022 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.gradle.spotless;
17+
18+
import java.io.IOException;
19+
20+
import org.assertj.core.api.Assertions;
21+
import org.gradle.testkit.runner.BuildResult;
22+
import org.junit.jupiter.api.Nested;
23+
import org.junit.jupiter.api.Test;
24+
import org.junit.jupiter.params.ParameterizedTest;
25+
import org.junit.jupiter.params.provider.ValueSource;
26+
27+
import com.diffplug.spotless.tag.NpmTest;
28+
29+
@NpmTest
30+
class JavascriptExtensionTest extends GradleIntegrationHarness {
31+
32+
@NpmTest
33+
@Nested
34+
class EslintGeneralJavascriptTests extends GradleIntegrationHarness {
35+
@Test
36+
void supportsEslintFormattingForJavascript() throws IOException {
37+
setFile(".eslintrc.js").toResource("npm/eslint/javascript/styleguide/standard/.eslintrc.js");
38+
setFile("build.gradle").toLines(
39+
"plugins {",
40+
" id 'com.diffplug.spotless'",
41+
"}",
42+
"repositories { mavenCentral() }",
43+
"spotless {",
44+
" javascript {",
45+
" target 'test.js'",
46+
" eslint().configFile('.eslintrc.js').styleGuide('standard')",
47+
" }",
48+
"}");
49+
setFile("test.js").toResource("npm/eslint/javascript/styleguide/standard/javascript-es6.dirty");
50+
gradleRunner().withArguments("--stacktrace", "spotlessApply").build();
51+
assertFile("test.js").sameAsResource("npm/eslint/javascript/styleguide/standard/javascript-es6.clean");
52+
}
53+
54+
@Test
55+
void eslintDoesNotAllowToUseTsStyleGuideForJavascript() throws IOException {
56+
setFile(".eslintrc.js").toResource("npm/eslint/javascript/styleguide/standard/.eslintrc.js");
57+
setFile("build.gradle").toLines(
58+
"plugins {",
59+
" id 'com.diffplug.spotless'",
60+
"}",
61+
"repositories { mavenCentral() }",
62+
"spotless {",
63+
" javascript {",
64+
" target 'test.js'",
65+
" eslint().configFile('.eslintrc.js').styleGuide('xo-typescript')",
66+
" }",
67+
"}");
68+
setFile("test.js").toResource("npm/eslint/javascript/styleguide/standard/javascript-es6.dirty");
69+
final BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail();
70+
Assertions.assertThat(spotlessApply.getOutput()).contains("Unknown style guide: xo-typescript");
71+
}
72+
73+
@Test
74+
void eslintAllowsToSpecifyEslintVersionForJavascript() throws IOException {
75+
setFile(".eslintrc.js").toResource("npm/eslint/javascript/styleguide/standard/.eslintrc.js");
76+
setFile("build.gradle").toLines(
77+
"plugins {",
78+
" id 'com.diffplug.spotless'",
79+
"}",
80+
"repositories { mavenCentral() }",
81+
"spotless {",
82+
" javascript {",
83+
" target 'test.js'",
84+
" eslint('8.28.0').configFile('.eslintrc.js').styleGuide('standard')",
85+
" }",
86+
"}");
87+
setFile("test.js").toResource("npm/eslint/javascript/styleguide/standard/javascript-es6.dirty");
88+
gradleRunner().withArguments("--stacktrace", "spotlessApply").build();
89+
assertFile("test.js").sameAsResource("npm/eslint/javascript/styleguide/standard/javascript-es6.clean");
90+
}
91+
92+
@Test
93+
void esllintAllowsToSpecifyInlineConfig() throws IOException {
94+
final String eslintConfigJs = String.join("\n",
95+
"{",
96+
" env: {",
97+
" browser: true,",
98+
" es2021: true",
99+
" },",
100+
" extends: 'standard',",
101+
" overrides: [",
102+
" ],",
103+
" parserOptions: {",
104+
" ecmaVersion: 'latest',",
105+
" sourceType: 'module'",
106+
" },",
107+
" rules: {",
108+
" }",
109+
"}");
110+
setFile("build.gradle").toLines(
111+
"plugins {",
112+
" id 'com.diffplug.spotless'",
113+
"}",
114+
"repositories { mavenCentral() }",
115+
"spotless {",
116+
" javascript {",
117+
" target 'test.js'",
118+
" eslint().configJs('''" + eslintConfigJs + "''').styleGuide('standard')",
119+
" }",
120+
"}");
121+
setFile("test.js").toResource("npm/eslint/javascript/styleguide/standard/javascript-es6.dirty");
122+
gradleRunner().withArguments("--stacktrace", "spotlessApply").build();
123+
assertFile("test.js").sameAsResource("npm/eslint/javascript/styleguide/standard/javascript-es6.clean");
124+
}
125+
126+
@Test
127+
void eslintRequiresAnExplicitEslintConfig() throws IOException {
128+
setFile(".eslintrc.js").toResource("npm/eslint/javascript/styleguide/standard/.eslintrc.js");
129+
setFile("build.gradle").toLines(
130+
"plugins {",
131+
" id 'com.diffplug.spotless'",
132+
"}",
133+
"repositories { mavenCentral() }",
134+
"spotless {",
135+
" javascript {",
136+
" target 'test.js'",
137+
" eslint().styleGuide('standard')",
138+
" }",
139+
"}");
140+
setFile("test.js").toResource("npm/eslint/javascript/styleguide/standard/javascript-es6.dirty");
141+
BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail();
142+
Assertions.assertThat(spotlessApply.getOutput()).contains("ESLint must be configured");
143+
}
144+
145+
@Test
146+
void eslintAllowsSpecifyingCustomLibraryVersions() throws IOException {
147+
setFile(".eslintrc.js").toResource("npm/eslint/javascript/styleguide/standard/.eslintrc.js");
148+
setFile("build.gradle").toLines(
149+
"plugins {",
150+
" id 'com.diffplug.spotless'",
151+
"}",
152+
"repositories { mavenCentral() }",
153+
"spotless {",
154+
" javascript {",
155+
" target 'test.js'",
156+
" eslint([",
157+
" 'eslint': '8.28.0',",
158+
" 'eslint-config-standard': '17.0.0',",
159+
" 'eslint-plugin-import': '2.26.0',",
160+
" 'eslint-plugin-n': '15.6.0',",
161+
" 'eslint-plugin-promise': '6.1.1'",
162+
" ]).configFile('.eslintrc.js')",
163+
" }",
164+
"}");
165+
setFile("test.js").toResource("npm/eslint/javascript/styleguide/standard/javascript-es6.dirty");
166+
gradleRunner().withArguments("--stacktrace", "spotlessApply").build();
167+
assertFile("test.js").sameAsResource("npm/eslint/javascript/styleguide/standard/javascript-es6.clean");
168+
}
169+
170+
}
171+
172+
@NpmTest
173+
@Nested
174+
class EslintPopularJsStyleGuideTests extends GradleIntegrationHarness {
175+
@ParameterizedTest(name = "{index}: eslint can be applied using styleguide {0}")
176+
@ValueSource(strings = {"airbnb", "google", "standard", "xo"})
177+
void formattingUsingStyleguide(String styleguide) throws Exception {
178+
179+
final String styleguidePath = "npm/eslint/javascript/styleguide/" + styleguide + "/";
180+
181+
setFile(".eslintrc.js").toResource(styleguidePath + ".eslintrc.js");
182+
setFile("build.gradle").toLines(
183+
"plugins {",
184+
" id 'com.diffplug.spotless'",
185+
"}",
186+
"repositories { mavenCentral() }",
187+
"spotless {",
188+
" javascript {",
189+
" target 'test.js'",
190+
" eslint().configFile('.eslintrc.js').styleGuide('" + styleguide + "')",
191+
" }",
192+
"}");
193+
setFile("test.js").toResource(styleguidePath + "javascript-es6.dirty");
194+
gradleRunner().withArguments("--stacktrace", "spotlessApply").build();
195+
assertFile("test.js").sameAsResource(styleguidePath + "javascript-es6.clean");
196+
}
197+
}
198+
199+
@NpmTest
200+
@Nested
201+
class JavascriptPrettierTests extends GradleIntegrationHarness {
202+
@Test
203+
void supportsPrettierFormattingForJavascript() throws IOException {
204+
setFile("build.gradle").toLines(
205+
"plugins {",
206+
" id 'com.diffplug.spotless'",
207+
"}",
208+
"repositories { mavenCentral() }",
209+
"spotless {",
210+
" javascript {",
211+
" target 'test.js'",
212+
" prettier()",
213+
" }",
214+
"}");
215+
setFile("test.js").toResource("npm/prettier/filetypes/javascript-es6/javascript-es6.dirty");
216+
gradleRunner().withArguments("--stacktrace", "spotlessApply").build();
217+
assertFile("test.js").sameAsResource("npm/prettier/filetypes/javascript-es6/javascript-es6.clean");
218+
}
219+
}
220+
221+
}

plugin-gradle/src/test/java/com/diffplug/gradle/spotless/TypescriptExtensionTest.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import java.io.IOException;
1919

20+
import org.assertj.core.api.Assertions;
21+
import org.gradle.testkit.runner.BuildResult;
2022
import org.junit.jupiter.api.Test;
2123

2224
import com.diffplug.spotless.tag.NpmTest;
@@ -162,7 +164,7 @@ void useEslint() throws IOException {
162164
}
163165

164166
@Test
165-
void useXoStandardRules() throws IOException {
167+
void useEslintXoStandardRules() throws IOException {
166168
setFile(".eslintrc.js").toResource("npm/eslint/typescript/styleguide/xo/.eslintrc.js");
167169
setFile("tsconfig.json").toResource("npm/eslint/typescript/styleguide/xo/tsconfig.json");
168170
setFile("build.gradle").toLines(
@@ -182,7 +184,7 @@ void useXoStandardRules() throws IOException {
182184
}
183185

184186
@Test
185-
void useStandardWithTypescriptRules() throws IOException {
187+
void useEslintStandardWithTypescriptRules() throws IOException {
186188
setFile(".eslintrc.js").toResource("npm/eslint/typescript/styleguide/standard_with_typescript/.eslintrc.js");
187189
setFile("tsconfig.json").toResource("npm/eslint/typescript/styleguide/standard_with_typescript/tsconfig.json");
188190
setFile("build.gradle").toLines(
@@ -200,4 +202,23 @@ void useStandardWithTypescriptRules() throws IOException {
200202
gradleRunner().withArguments("--stacktrace", "spotlessApply").build();
201203
assertFile("test.ts").sameAsResource("npm/eslint/typescript/styleguide/standard_with_typescript/typescript.clean");
202204
}
205+
206+
@Test
207+
void useEslintForTypescriptDoesNotAllowUsingJsStyleguide() throws IOException {
208+
setFile(".eslintrc.js").toResource("npm/eslint/javascript/styleguide/airbnb/.eslintrc.js");
209+
setFile("build.gradle").toLines(
210+
"plugins {",
211+
" id 'com.diffplug.spotless'",
212+
"}",
213+
"repositories { mavenCentral() }",
214+
"spotless {",
215+
" typescript {",
216+
" target 'test.ts'",
217+
" eslint().styleGuide('airbnb').configFile('.eslintrc.js')",
218+
" }",
219+
"}");
220+
setFile("test.js").toResource("npm/eslint/javascript/styleguide/airbnb/javascript-es6.dirty");
221+
BuildResult spotlessApply = gradleRunner().withArguments("--stacktrace", "spotlessApply").buildAndFail();
222+
Assertions.assertThat(spotlessApply.getOutput()).contains("Unknown style guide: airbnb");
223+
}
203224
}

0 commit comments

Comments
 (0)