Skip to content

Commit daefe4c

Browse files
committed
feat: improve class/enum/interface/record clause wrapping/indentation
1 parent dc42509 commit daefe4c

File tree

15 files changed

+584
-53
lines changed

15 files changed

+584
-53
lines changed

packages/prettier-plugin-java/src/printers/classes.ts

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { AstPath, Doc } from "prettier";
66
import { builders } from "prettier/doc";
77
import {
88
call,
9+
definedKeys,
910
each,
1011
hasDeclarationAnnotations,
1112
hasLeadingComments,
@@ -42,33 +43,49 @@ export default {
4243
},
4344

4445
normalClassDeclaration(path, print) {
45-
const { classExtends, classImplements, classPermits, typeParameters } =
46-
path.node.children;
47-
const header = ["class ", call(path, print, "typeIdentifier")];
48-
if (typeParameters) {
49-
header.push(call(path, print, "typeParameters"));
50-
}
51-
if (classExtends) {
52-
header.push(indent([line, call(path, print, "classExtends")]));
53-
}
54-
if (classImplements) {
55-
header.push(indent([line, call(path, print, "classImplements")]));
46+
const { children } = path.node;
47+
const definedClauses = definedKeys(children, [
48+
"classExtends",
49+
"classImplements",
50+
"classPermits"
51+
]);
52+
const hasMultipleClauses = definedClauses.length > 1;
53+
const hasTypeParameters = children.typeParameters !== undefined;
54+
const parts = ["class ", call(path, print, "typeIdentifier")];
55+
if (hasTypeParameters) {
56+
const typeParameters = call(path, print, "typeParameters");
57+
parts.push(
58+
hasMultipleClauses ? group(indent(typeParameters)) : typeParameters
59+
);
5660
}
57-
if (classPermits) {
58-
header.push(indent([line, call(path, print, "classPermits")]));
61+
if (definedClauses.length) {
62+
const separator = hasTypeParameters && !hasMultipleClauses ? " " : line;
63+
const clauses = definedClauses.flatMap(clause => [
64+
separator,
65+
call(path, print, clause)
66+
]);
67+
const hasBody =
68+
children.classBody[0].children.classBodyDeclaration !== undefined;
69+
const clauseGroup = [
70+
hasTypeParameters && !hasMultipleClauses ? clauses : indent(clauses),
71+
hasBody ? separator : " "
72+
];
73+
parts.push(hasMultipleClauses ? clauseGroup : group(clauseGroup));
74+
} else {
75+
parts.push(" ");
5976
}
60-
return [group(header), " ", call(path, print, "classBody")];
77+
return [group(parts), call(path, print, "classBody")];
6178
},
6279

6380
classModifier: printSingle,
6481

6582
typeParameters(path, print) {
66-
return group([
83+
return [
6784
"<",
6885
indent([softline, call(path, print, "typeParameterList")]),
6986
softline,
7087
">"
71-
]);
88+
];
7289
},
7390

7491
typeParameterList(path, print) {
@@ -89,7 +106,7 @@ export default {
89106
classPermits: printClassPermits,
90107

91108
interfaceTypeList(path, print) {
92-
return group(printList(path, print, "interfaceType"));
109+
return printList(path, print, "interfaceType");
93110
},
94111

95112
classBody(path, print) {
@@ -199,7 +216,7 @@ export default {
199216
const { typeParameters, annotation, throws } = path.node.children;
200217
const header: Doc[] = [];
201218
if (typeParameters) {
202-
header.push(call(path, print, "typeParameters"));
219+
header.push(group(call(path, print, "typeParameters")));
203220
}
204221
if (annotation) {
205222
header.push(join(line, map(path, print, "annotation")));
@@ -322,7 +339,7 @@ export default {
322339
: "()"
323340
);
324341
return children.typeParameters
325-
? [call(path, print, "typeParameters"), " ", ...header]
342+
? [group(call(path, print, "typeParameters")), " ", ...header]
326343
: header;
327344
},
328345

@@ -379,11 +396,21 @@ export default {
379396
},
380397

381398
enumDeclaration(path, print) {
382-
const header = ["enum", call(path, print, "typeIdentifier")];
383-
if (path.node.children.classImplements) {
384-
header.push(call(path, print, "classImplements"));
399+
const { children } = path.node;
400+
const parts = ["enum ", call(path, print, "typeIdentifier")];
401+
if (children.classImplements) {
402+
const body = children.enumBody[0].children;
403+
const hasBody =
404+
body.enumBodyDeclarations !== undefined ||
405+
body.enumConstantList !== undefined;
406+
parts.push(
407+
indent([line, call(path, print, "classImplements")]),
408+
hasBody ? line : " "
409+
);
410+
} else {
411+
parts.push(" ");
385412
}
386-
return join(" ", [...header, call(path, print, "enumBody")]);
413+
return [group(parts), call(path, print, "enumBody")];
387414
},
388415

389416
enumBody(path, print, options) {
@@ -445,20 +472,40 @@ export default {
445472

446473
recordDeclaration(path, print) {
447474
const { children } = path.node;
448-
const header = ["record ", call(path, print, "typeIdentifier")];
475+
const parts = ["record ", call(path, print, "typeIdentifier")];
449476
if (children.typeParameters) {
450-
header.push(call(path, print, "typeParameters"));
477+
parts.push(group(call(path, print, "typeParameters")));
451478
}
452-
header.push(call(path, print, "recordHeader"));
479+
parts.push(call(path, print, "recordHeader"));
453480
if (children.classImplements) {
454-
header.push(" ", call(path, print, "classImplements"));
481+
const hasComponents =
482+
children.recordHeader[0].children.recordComponentList !== undefined;
483+
const hasBody =
484+
children.recordBody[0].children.recordBodyDeclaration !== undefined;
485+
const classImplements = [
486+
hasComponents ? " " : line,
487+
call(path, print, "classImplements")
488+
];
489+
parts.push(
490+
group([
491+
hasComponents ? classImplements : indent(classImplements),
492+
hasBody ? line : " "
493+
])
494+
);
495+
} else {
496+
parts.push(" ");
455497
}
456-
return [group(header), " ", call(path, print, "recordBody")];
498+
return [group(parts), call(path, print, "recordBody")];
457499
},
458500

459501
recordHeader(path, print) {
460502
return path.node.children.recordComponentList
461-
? indentInParentheses(call(path, print, "recordComponentList"))
503+
? [
504+
"(",
505+
indent([softline, call(path, print, "recordComponentList")]),
506+
softline,
507+
")"
508+
]
462509
: indentInParentheses(printDanglingComments(path), { shouldBreak: true });
463510
},
464511

packages/prettier-plugin-java/src/printers/helpers.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,7 @@ export function printClassPermits(
295295
path: AstPath<ClassPermitsCstNode | InterfacePermitsCstNode>,
296296
print: JavaPrintFn
297297
) {
298-
return group([
299-
"permits",
300-
indent([line, group(printList(path, print, "typeName"))])
301-
]);
298+
return group(["permits", indent([line, printList(path, print, "typeName")])]);
302299
}
303300

304301
export function printClassType(

packages/prettier-plugin-java/src/printers/interfaces.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Doc } from "prettier";
22
import { builders } from "prettier/doc";
33
import {
44
call,
5+
definedKeys,
56
each,
67
hasDeclarationAnnotations,
78
indentInParentheses,
@@ -35,19 +36,38 @@ export default {
3536
},
3637

3738
normalInterfaceDeclaration(path, print) {
38-
const { interfaceExtends, interfacePermits, typeParameters } =
39-
path.node.children;
40-
const header = ["interface ", call(path, print, "typeIdentifier")];
41-
if (typeParameters) {
42-
header.push(call(path, print, "typeParameters"));
43-
}
44-
if (interfaceExtends) {
45-
header.push(indent([line, call(path, print, "interfaceExtends")]));
39+
const { children } = path.node;
40+
const definedClauses = definedKeys(children, [
41+
"interfaceExtends",
42+
"interfacePermits"
43+
]);
44+
const hasMultipleClauses = definedClauses.length > 1;
45+
const hasTypeParameters = children.typeParameters !== undefined;
46+
const parts = ["interface ", call(path, print, "typeIdentifier")];
47+
if (hasTypeParameters) {
48+
const typeParameters = call(path, print, "typeParameters");
49+
parts.push(
50+
hasMultipleClauses ? group(indent(typeParameters)) : typeParameters
51+
);
4652
}
47-
if (interfacePermits) {
48-
header.push(indent([line, call(path, print, "interfacePermits")]));
53+
if (definedClauses.length) {
54+
const separator = hasTypeParameters && !hasMultipleClauses ? " " : line;
55+
const clauses = definedClauses.flatMap(clause => [
56+
separator,
57+
call(path, print, clause)
58+
]);
59+
const hasBody =
60+
children.interfaceBody[0].children.interfaceMemberDeclaration !==
61+
undefined;
62+
const clauseGroup = [
63+
hasTypeParameters && !hasMultipleClauses ? clauses : indent(clauses),
64+
hasBody ? separator : " "
65+
];
66+
parts.push(hasMultipleClauses ? clauseGroup : group(clauseGroup));
67+
} else {
68+
parts.push(" ");
4969
}
50-
return [group(header), " ", call(path, print, "interfaceBody")];
70+
return [group(parts), call(path, print, "interfaceBody")];
5171
},
5272

5373
interfaceModifier: printSingle,

packages/prettier-plugin-java/test/unit-test/classes/_input.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,46 @@ class ClassWithSemicolon {
2121
;
2222
private FieldOneClass fieldOne;
2323
}
24+
25+
class Aaaaaaaaaa<Bbbbbbbbbb> extends Cccccccccc implements Dddddddddd {
26+
27+
void a() {}
28+
}
29+
30+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc> extends Dddddddddd implements Eeeeeeeeee {
31+
32+
void a() {}
33+
}
34+
35+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc> extends Dddddddddd implements Eeeeeeeeee {}
36+
37+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc> extends Dddddddddd<Eeeeeeeeee, Ffffffffff> {
38+
39+
void a() {}
40+
}
41+
42+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc> extends Dddddddddd<Eeeeeeeeee, Ffffffffff, Gggggggggg, Hhhhhhhhhh, Iiiiiiiiii> {
43+
44+
void a() {}
45+
}
46+
47+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc> extends Dddddddddd<Eeeeeeeeee, Ffffffffff> implements Gggggggggg, Hhhhhhhhhh {
48+
49+
void a() {}
50+
}
51+
52+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc> extends Dddddddddd<Eeeeeeeeee, Ffffffffff> implements Gggggggggg, Hhhhhhhhhh {}
53+
54+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc, Dddddddddd, Eeeeeeeeee, Ffffffffff, Gggggggggg> extends Hhhhhhhhhh<Iiiiiiiiii, Jjjjjjjjjj> implements Kkkkkkkkkk, Llllllllll {
55+
56+
void a() {}
57+
}
58+
59+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc, Dddddddddd, Eeeeeeeeee, Ffffffffff, Gggggggggg> extends Hhhhhhhhhh<Iiiiiiiiii, Jjjjjjjjjj> implements Kkkkkkkkkk, Llllllllll {}
60+
61+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc, Dddddddddd, Eeeeeeeeee, Ffffffffff, Gggggggggg> extends Hhhhhhhhhh<Iiiiiiiiii, Jjjjjjjjjj, Kkkkkkkkkk, Llllllllll, Mmmmmmmmmm, Nnnnnnnnnn> implements Oooooooooo, Pppppppppp, Qqqqqqqqqq, Rrrrrrrrrr, Ssssssssss, Tttttttttt, Uuuuuuuuuu {
62+
63+
void a() {}
64+
}
65+
66+
class Aaaaaaaaaa<Bbbbbbbbbb, Cccccccccc, Dddddddddd, Eeeeeeeeee, Ffffffffff, Gggggggggg> extends Hhhhhhhhhh<Iiiiiiiiii, Jjjjjjjjjj, Kkkkkkkkkk, Llllllllll, Mmmmmmmmmm, Nnnnnnnnnn> implements Oooooooooo, Pppppppppp, Qqqqqqqqqq, Rrrrrrrrrr, Ssssssssss, Tttttttttt, Uuuuuuuuuu {}

0 commit comments

Comments
 (0)