@@ -37,18 +37,38 @@ public class RomeStep {
37
37
*/
38
38
private final String configPath ;
39
39
40
+ /**
41
+ * The language (syntax) of the input files to format. When <code>null</code> or
42
+ * the empty string, the language is detected automatically from the file name.
43
+ * Currently the following languages are supported by Rome:
44
+ * <ul>
45
+ * <li>js (JavaScript)</li>
46
+ * <li>jsx (JavaScript + JSX)</li>
47
+ * <li>js? (JavaScript or JavaScript + JSX, depending on the file
48
+ * extension)</li>
49
+ * <li>ts (TypeScript)</li>
50
+ * <li>tsx (TypeScript + JSX)</li>
51
+ * <li>ts? (TypeScript or TypeScript + JSX, depending on the file
52
+ * extension)</li>
53
+ * <li>json (JSON)</li>
54
+ * </ul>
55
+ */
56
+ private final String language ;
57
+
40
58
/**
41
59
* Path to the Rome executable. Can be <code>null</code>, but either a path to
42
- * the executable of a download directory and version must be given.
60
+ * the executable of a download directory and version must be given. The path
61
+ * must be either an absolute path, or a file name without path separators. If
62
+ * the latter, it is interpreted as a command in the user's path.
43
63
*/
44
64
private final String pathToExe ;
45
65
46
66
/**
47
- * Path to the download directory for storing the download Rome executable. Can
48
- * be <code>null</code>, but either a path to the executable of a download
49
- * directory and version must be given.
67
+ * Absolute path to the download directory for storing the download Rome
68
+ * executable. Can be <code>null</code>, but either a path to the executable of
69
+ * a download directory and version must be given.
50
70
*/
51
- private final String pathToExeDownloadDir ;
71
+ private final String downloadDir ;
52
72
53
73
/**
54
74
* Version of Rome to download. Can be <code>null</code>, but either a path to
@@ -71,9 +91,8 @@ public static String name() {
71
91
* @param downloadDir Directory where to place the downloaded executable.
72
92
* @return A new Rome step that download the executable from the network.
73
93
*/
74
- public static RomeStep withExeDownload (String version , String downloadDir ) {
75
- version = version != null && !version .isBlank () ? version : defaultVersion ();
76
- return new RomeStep (version , null , downloadDir , null );
94
+ public static RomeStep .Builder withExeDownload (String version , String downloadDir ) {
95
+ return new RomeStep .Builder (version , null , downloadDir );
77
96
}
78
97
79
98
/**
@@ -83,8 +102,8 @@ public static RomeStep withExeDownload(String version, String downloadDir) {
83
102
* @param pathToExe Path to the Rome executable to use.
84
103
* @return A new Rome step that format with the given executable.
85
104
*/
86
- public static RomeStep withExePath (String pathToExe ) {
87
- return new RomeStep (null , pathToExe , null , null );
105
+ public static RomeStep . Builder withExePath (String pathToExe ) {
106
+ return new RomeStep . Builder (null , pathToExe , null );
88
107
}
89
108
90
109
/**
@@ -180,14 +199,16 @@ private static void validateRomeExecutable(String resolvedPathToExe) {
180
199
}
181
200
182
201
/**
183
- * Checks the Rome executable. When the executable path does not exist, an error
184
- * is thrown.
202
+ * Creates a new Rome step with the configuration from the given builder.
203
+ *
204
+ * @param builder Builder with the configuration to use.
185
205
*/
186
- private RomeStep (String version , String pathToExe , String pathToExeDownloadDir , String configPath ) {
187
- this .version = version ;
188
- this .pathToExe = pathToExe ;
189
- this .pathToExeDownloadDir = pathToExeDownloadDir ;
190
- this .configPath = configPath ;
206
+ private RomeStep (RomeStep .Builder builder ) {
207
+ this .version = builder .version != null && !builder .version .isBlank () ? builder .version : defaultVersion ();
208
+ this .pathToExe = builder .pathToExe ;
209
+ this .downloadDir = builder .downloadDir ;
210
+ this .configPath = builder .configPath ;
211
+ this .language = builder .language ;
191
212
}
192
213
193
214
/**
@@ -200,19 +221,6 @@ public FormatterStep create() {
200
221
return FormatterStep .createLazy (name (), this ::createState , State ::toFunc );
201
222
}
202
223
203
- /**
204
- * Derives a new Rome step from this step by replacing the config path with the
205
- * given value.
206
- *
207
- * @param configPath Config path to use. Must point to a directory which contain
208
- * a file named {@code rome.json}.
209
- * @return A new Rome step with the same configuration as this step, but with
210
- * the given config file instead.
211
- */
212
- public RomeStep withConfigPath (String configPath ) {
213
- return new RomeStep (version , pathToExe , pathToExeDownloadDir , configPath );
214
- }
215
-
216
224
/**
217
225
* Resolves the Rome executable, possibly downloading it from the network, and
218
226
* creates a new state instance with the resolved executable that can format
@@ -234,7 +242,7 @@ private State createState() throws IOException, InterruptedException {
234
242
logger .debug ("Using Rome executable located at '{}'" , resolvedPathToExe );
235
243
var exeSignature = FileSignature .signAsList (Collections .singleton (new File (resolvedPathToExe )));
236
244
makeExecutable (resolvedPathToExe );
237
- return new State (resolvedPathToExe , exeSignature , configPath );
245
+ return new State (resolvedPathToExe , exeSignature , configPath , language );
238
246
}
239
247
240
248
/**
@@ -261,13 +269,95 @@ private String resolveExe() throws IOException, InterruptedException {
261
269
return pathToExe ;
262
270
}
263
271
} else {
264
- var downloader = new RomeExecutableDownloader (Paths .get (pathToExeDownloadDir ));
272
+ var downloader = new RomeExecutableDownloader (Paths .get (downloadDir ));
265
273
var downloaded = downloader .ensureDownloaded (version ).toString ();
266
274
makeExecutable (downloaded );
267
275
return downloaded ;
268
276
}
269
277
}
270
278
279
+ public final static class Builder {
280
+ /** See {@link RomeStep#configPath} */
281
+ private String configPath ;
282
+
283
+ /** See {@link RomeStep#downloadDir} */
284
+ private final String downloadDir ;
285
+
286
+ /** See {@link RomeStep#language} */
287
+ private String language ;
288
+
289
+ /** See {@link RomeStep#pathToExe} */
290
+ private final String pathToExe ;
291
+
292
+ /** See {@link RomeStep#version} */
293
+ private final String version ;
294
+
295
+ /**
296
+ * Creates a new builder for configuring a Rome step that can format code via
297
+ * Rome. Either a version and and downloadDir, or a pathToExe must be given.
298
+ *
299
+ * @param version The version of Rome to download, see
300
+ * {@link RomeStep#version}.
301
+ * @param pathToExe The path to the Rome executable to use, see
302
+ * {@link RomeStep#pathToExe}.
303
+ * @param downloadDir The path to the download directory when downloading Rome
304
+ * from the network, {@link RomeStep#downloadDir}.
305
+ */
306
+ private Builder (String version , String pathToExe , String downloadDir ) {
307
+ this .version = version ;
308
+ this .pathToExe = pathToExe ;
309
+ this .downloadDir = downloadDir ;
310
+ }
311
+
312
+ /**
313
+ * Creates a new Rome step for formatting code with Rome from the current
314
+ * configuration of this builder.
315
+ *
316
+ * @return A new Rome step with the current configuration.
317
+ */
318
+ public RomeStep build () {
319
+ return new RomeStep (this );
320
+ }
321
+
322
+ /**
323
+ * Sets the path to the directory with the {@code rome.json} config file. When
324
+ * no config path is set, the default configuration is used.
325
+ *
326
+ * @param configPath Config path to use. Must point to a directory which contain
327
+ * a file named {@code rome.json}.
328
+ * @return This builder instance for chaining method calls.
329
+ */
330
+ public Builder withConfigPath (String configPath ) {
331
+ this .configPath = configPath ;
332
+ return this ;
333
+ }
334
+
335
+ /**
336
+ * Sets the language of the files to format When no language is set, it is
337
+ * determined automatically from the file name. The following languages are
338
+ * currently supported by Rome.
339
+ *
340
+ * <ul>
341
+ * <li>js (JavaScript)</li>
342
+ * <li>jsx (JavaScript + JSX)</li>
343
+ * <li>js? (JavaScript or JavaScript + JSX, depending on the file
344
+ * extension)</li>
345
+ * <li>ts (TypeScript)</li>
346
+ * <li>tsx (TypeScript + JSX)</li>
347
+ * <li>ts? (TypeScript or TypeScript + JSX, depending on the file
348
+ * extension)</li>
349
+ * <li>json (JSON)</li>
350
+ * </ul>
351
+ *
352
+ * @param language The language of the files to format.
353
+ * @return This builder instance for chaining method calls.
354
+ */
355
+ public Builder withLanguage (String language ) {
356
+ this .language = language ;
357
+ return this ;
358
+ }
359
+ }
360
+
271
361
/**
272
362
* The internal state used by the Rome formatter. A state instance is created
273
363
* when the spotless plugin for Maven or Gradle is executed, and reused for all
@@ -293,6 +383,12 @@ private static class State implements Serializable {
293
383
*/
294
384
private final String configPath ;
295
385
386
+ /**
387
+ * The language of the files to format. When <code>null</code> or the empty
388
+ * string, the language is detected from the file name.
389
+ */
390
+ private final String language ;
391
+
296
392
/**
297
393
* Creates a new state for instance which can format code with the given Rome
298
394
* executable.
@@ -303,10 +399,11 @@ private static class State implements Serializable {
303
399
* config file, can be <code>null</code>, in which case the
304
400
* defaults are used.
305
401
*/
306
- private State (String exe , FileSignature exeSignature , String configPath ) {
402
+ private State (String exe , FileSignature exeSignature , String configPath , String language ) {
307
403
this .pathToExe = exe ;
308
404
this .exeSignature = exeSignature ;
309
405
this .configPath = configPath ;
406
+ this .language = language ;
310
407
}
311
408
312
409
/**
@@ -317,11 +414,12 @@ private State(String exe, FileSignature exeSignature, String configPath) {
317
414
* @return The Rome command to use for formatting code.
318
415
*/
319
416
private String [] buildRomeCommand (File file ) {
417
+ var fileName = resolveFileName (file );
320
418
var argList = new ArrayList <String >();
321
419
argList .add (pathToExe );
322
420
argList .add ("format" );
323
421
argList .add ("--stdin-file-path" );
324
- argList .add (file . getName () );
422
+ argList .add (fileName );
325
423
if (configPath != null ) {
326
424
argList .add ("--config-path" );
327
425
argList .add (configPath );
@@ -352,6 +450,47 @@ private String format(ProcessRunner runner, String input, File file) throws IOEx
352
450
return runner .exec (stdin , args ).assertExitZero (StandardCharsets .UTF_8 );
353
451
}
354
452
453
+ /**
454
+ * The Rome executable currently does not have a parameter to specify the
455
+ * expected language / syntax. Rome always determined the language from the file
456
+ * extension. This method returns the file name for the desired language when a
457
+ * language was requested explicitly, or the file name of the input file for
458
+ * auto detection.
459
+ *
460
+ * @param file File to be formatted.
461
+ * @return The file name to pass to the Rome executable.
462
+ */
463
+ private String resolveFileName (File file ) {
464
+ var name = file .getName ();
465
+ if (language == null || language .isBlank ()) {
466
+ return name ;
467
+ }
468
+ var dot = name .lastIndexOf ("." );
469
+ var ext = dot >= 0 ? name .substring (dot + 1 ) : name ;
470
+ switch (language ) {
471
+ case "js?" :
472
+ return "jsx" .equals (ext ) || "js" .equals (ext ) || "mjs" .equals (ext ) || "cjs" .equals (ext ) ? name
473
+ : "file.js" ;
474
+ case "ts?" :
475
+ return "tsx" .equals (ext ) || "ts" .equals (ext ) || "tjs" .equals (ext ) || "tjs" .equals (ext ) ? name
476
+ : "file.js" ;
477
+ case "js" :
478
+ return "js" .equals (ext ) || "mjs" .equals (ext ) || "cjs" .equals (ext ) ? name : "file.js" ;
479
+ case "jsx" :
480
+ return "jsx" .equals (ext ) ? name : "file.jsx" ;
481
+ case "ts" :
482
+ return "ts" .equals (ext ) || "mts" .equals (ext ) || "cts" .equals (ext ) ? name : "file.ts" ;
483
+ case "tsx" :
484
+ return "tsx" .equals (ext ) ? name : "file.tsx" ;
485
+ case "json" :
486
+ return "json" .equals (ext ) ? name : "file.json" ;
487
+ // so that we can support new languages such as css or yaml when Rome adds
488
+ // support for them without having to change the code
489
+ default :
490
+ return "file." + language ;
491
+ }
492
+ }
493
+
355
494
/**
356
495
* Creates a new formatter function for formatting a piece of code by delegating
357
496
* to the Rome executable.
0 commit comments