prettier-plugin-java 2.7.6 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- Copyright 2018-2025 the original author or authors from the JHipster project
2
+ Copyright 2018-2026 the original author or authors from the JHipster project
3
3
 
4
4
  Apache License
5
5
  Version 2.0, January 2004
@@ -1,8 +1,8 @@
1
1
  import type { IToken } from "java-parser";
2
2
  import { type AstPath } from "prettier";
3
3
  import { type JavaNode, type JavaNonTerminal, type JavaParserOptions } from "./printers/helpers.js";
4
- export declare function determineFormatterOffOnRanges(cst: JavaNonTerminal): void;
5
- export declare function isFullyBetweenFormatterOffOn(path: AstPath<JavaNode>): boolean;
4
+ export declare function determinePrettierIgnoreRanges(cst: JavaNonTerminal): void;
5
+ export declare function isFullyBetweenPrettierIgnore(path: AstPath<JavaNode>): boolean;
6
6
  export declare function canAttachComment(node: JavaNode): boolean;
7
7
  export declare function handleLineComment(commentNode: JavaComment, _: string, options: JavaParserOptions): boolean;
8
8
  export declare function handleRemainingComment(commentNode: JavaComment): boolean;
package/dist/comments.js CHANGED
@@ -1,35 +1,35 @@
1
1
  import { util } from "prettier";
2
2
  import parser from "./parser.js";
3
3
  import { isEmptyStatement, isNonTerminal, isTerminal } from "./printers/helpers.js";
4
- const formatterOffOnRangesByCst = new WeakMap();
5
- export function determineFormatterOffOnRanges(cst) {
4
+ const prettierIgnoreRangesByCst = new WeakMap();
5
+ export function determinePrettierIgnoreRanges(cst) {
6
6
  const { comments } = cst;
7
7
  if (!comments) {
8
8
  return;
9
9
  }
10
10
  const ranges = comments
11
- .filter(({ image }) => /^(\/\/\s*@formatter:(off|on)\s*|\/\*\s*@formatter:(off|on)\s*\*\/)$/.test(image))
11
+ .filter(({ image }) => /^\/(?:\/\s*(?:prettier-ignore-(?:start|end)|@formatter:(?:off|on))\s*|\*\s*(?:prettier-ignore-(?:start|end)|@formatter:(?:off|on))\s*\*\/)$/.test(image))
12
12
  .reduce((ranges, { image, startOffset }) => {
13
13
  const previous = ranges.at(-1);
14
- if (image.endsWith("off")) {
15
- if ((previous === null || previous === void 0 ? void 0 : previous.on) !== Infinity) {
16
- ranges.push({ off: startOffset, on: Infinity });
14
+ if (image.includes("start") || image.includes("off")) {
15
+ if ((previous === null || previous === void 0 ? void 0 : previous.end) !== Infinity) {
16
+ ranges.push({ start: startOffset, end: Infinity });
17
17
  }
18
18
  }
19
- else if ((previous === null || previous === void 0 ? void 0 : previous.on) === Infinity) {
20
- previous.on = startOffset;
19
+ else if ((previous === null || previous === void 0 ? void 0 : previous.end) === Infinity) {
20
+ previous.end = startOffset;
21
21
  }
22
22
  return ranges;
23
23
  }, new Array());
24
- formatterOffOnRangesByCst.set(cst, ranges);
24
+ prettierIgnoreRangesByCst.set(cst, ranges);
25
25
  }
26
- export function isFullyBetweenFormatterOffOn(path) {
26
+ export function isFullyBetweenPrettierIgnore(path) {
27
27
  var _a;
28
28
  const { node, root } = path;
29
29
  const start = parser.locStart(node);
30
30
  const end = parser.locEnd(node);
31
- return (((_a = formatterOffOnRangesByCst
32
- .get(root)) === null || _a === void 0 ? void 0 : _a.some(range => range.off < start && end < range.on)) === true);
31
+ return (((_a = prettierIgnoreRangesByCst
32
+ .get(root)) === null || _a === void 0 ? void 0 : _a.some(range => range.start < start && end < range.end)) === true);
33
33
  }
34
34
  export function canAttachComment(node) {
35
35
  var _a, _b, _c;
@@ -72,7 +72,8 @@ export function handleLineComment(commentNode, _, options) {
72
72
  handleIfStatementComments,
73
73
  handleJumpStatementComments,
74
74
  handleLabeledStatementComments,
75
- handleNameComments
75
+ handleNameComments,
76
+ handleTryStatementComments
76
77
  ].some(fn => fn(commentNode, options));
77
78
  }
78
79
  export function handleRemainingComment(commentNode) {
@@ -192,6 +193,33 @@ function handleNameComments(commentNode) {
192
193
  }
193
194
  return false;
194
195
  }
196
+ function handleTryStatementComments(commentNode) {
197
+ var _a, _b;
198
+ const { enclosingNode, followingNode } = commentNode;
199
+ if (enclosingNode &&
200
+ ["catches", "tryStatement"].includes(enclosingNode.name) &&
201
+ followingNode &&
202
+ isNonTerminal(followingNode)) {
203
+ const block = (_a = (followingNode.name === "catches"
204
+ ? followingNode.children.catchClause[0]
205
+ : followingNode.name === "catchClause" ||
206
+ followingNode.name === "finally"
207
+ ? followingNode
208
+ : null)) === null || _a === void 0 ? void 0 : _a.children.block[0];
209
+ if (!block) {
210
+ return false;
211
+ }
212
+ const blockStatement = (_b = block.children.blockStatements) === null || _b === void 0 ? void 0 : _b[0].children.blockStatement[0];
213
+ if (blockStatement) {
214
+ util.addLeadingComment(blockStatement, commentNode);
215
+ }
216
+ else {
217
+ util.addDanglingComment(block, commentNode, undefined);
218
+ }
219
+ return true;
220
+ }
221
+ return false;
222
+ }
195
223
  function isBinaryOperator(node) {
196
224
  var _a;
197
225
  return (node !== undefined &&
package/dist/parser.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parse } from "java-parser";
2
- import { determineFormatterOffOnRanges } from "./comments.js";
2
+ import { determinePrettierIgnoreRanges } from "./comments.js";
3
3
  import { isTerminal } from "./printers/helpers.js";
4
4
  export default {
5
5
  parse(text, options) {
@@ -8,7 +8,7 @@ export default {
8
8
  (_a = cst.comments) === null || _a === void 0 ? void 0 : _a.forEach(comment => {
9
9
  comment.value = comment.image;
10
10
  });
11
- determineFormatterOffOnRanges(cst);
11
+ determinePrettierIgnoreRanges(cst);
12
12
  return cst;
13
13
  },
14
14
  astFormat: "java",
package/dist/printer.js CHANGED
@@ -1,4 +1,4 @@
1
- import { canAttachComment, handleLineComment, handleRemainingComment, isFullyBetweenFormatterOffOn } from "./comments.js";
1
+ import { canAttachComment, handleLineComment, handleRemainingComment, isFullyBetweenPrettierIgnore } from "./comments.js";
2
2
  import { isNonTerminal, isTerminal, printComment } from "./printers/helpers.js";
3
3
  import { printerForNodeType } from "./printers/index.js";
4
4
  export default {
@@ -11,7 +11,7 @@ export default {
11
11
  var _a;
12
12
  const { node } = path;
13
13
  return (((_a = node.comments) === null || _a === void 0 ? void 0 : _a.some(({ image }) => /^(\/\/\s*prettier-ignore|\/\*\s*prettier-ignore\s*\*\/)$/.test(image))) === true ||
14
- (canAttachComment(node) && isFullyBetweenFormatterOffOn(path)));
14
+ (canAttachComment(node) && isFullyBetweenPrettierIgnore(path)));
15
15
  },
16
16
  canAttachComment,
17
17
  isBlockComment(node) {
@@ -12,7 +12,7 @@ declare const _default: {
12
12
  classModifier: typeof printSingle;
13
13
  typeParameters(path: AstPath<import("java-parser").TypeParametersCstNode & {
14
14
  comments?: import("../comments.js").JavaComment[];
15
- }>, print: JavaPrintFn): builders.Group;
15
+ }>, print: JavaPrintFn): (string | builders.Indent | builders.Softline)[];
16
16
  typeParameterList(path: AstPath<import("java-parser").TypeParameterListCstNode & {
17
17
  comments?: import("../comments.js").JavaComment[];
18
18
  }>, print: JavaPrintFn): builders.Doc[];
@@ -25,7 +25,7 @@ declare const _default: {
25
25
  classPermits: typeof printClassPermits;
26
26
  interfaceTypeList(path: AstPath<import("java-parser").InterfaceTypeListCstNode & {
27
27
  comments?: import("../comments.js").JavaComment[];
28
- }>, print: JavaPrintFn): builders.Group;
28
+ }>, print: JavaPrintFn): builders.Doc[];
29
29
  classBody(path: AstPath<ClassBodyCstNode & {
30
30
  comments?: import("../comments.js").JavaComment[];
31
31
  }>, print: JavaPrintFn): builders.Group | (string | builders.Indent | builders.Hardline)[] | "{}";
@@ -135,7 +135,7 @@ declare const _default: {
135
135
  }>, print: JavaPrintFn): builders.Doc[];
136
136
  recordHeader(path: AstPath<import("java-parser").RecordHeaderCstNode & {
137
137
  comments?: import("../comments.js").JavaComment[];
138
- }>, print: JavaPrintFn): builders.Group | "()";
138
+ }>, print: JavaPrintFn): builders.Group | (string | builders.Indent | builders.Softline)[] | "()";
139
139
  recordComponentList(path: AstPath<import("java-parser").RecordComponentListCstNode & {
140
140
  comments?: import("../comments.js").JavaComment[];
141
141
  }>, print: JavaPrintFn): builders.Doc[];
@@ -1,5 +1,5 @@
1
1
  import { builders } from "prettier/doc";
2
- import { call, each, hasDeclarationAnnotations, hasLeadingComments, indentInParentheses, isBinaryExpression, lineEndWithComments, lineStartWithComments, map, onlyDefinedKey, printBlock, printClassPermits, printClassType, printDanglingComments, printList, printSingle, printWithModifiers } from "./helpers.js";
2
+ import { call, definedKeys, each, hasDeclarationAnnotations, hasLeadingComments, hasNonAssignmentOperators, indentInParentheses, lineEndWithComments, lineStartWithComments, map, onlyDefinedKey, printBlock, printClassPermits, printClassType, printDanglingComments, printList, printSingle, printWithModifiers } from "./helpers.js";
3
3
  const { group, hardline, indent, indentIfBreak, join, line, softline } = builders;
4
4
  export default {
5
5
  classDeclaration(path, print) {
@@ -12,30 +12,45 @@ export default {
12
12
  return printWithModifiers(path, print, "classModifier", declaration, true);
13
13
  },
14
14
  normalClassDeclaration(path, print) {
15
- const { classExtends, classImplements, classPermits, typeParameters } = path.node.children;
16
- const header = ["class ", call(path, print, "typeIdentifier")];
17
- if (typeParameters) {
18
- header.push(call(path, print, "typeParameters"));
19
- }
20
- if (classExtends) {
21
- header.push(indent([line, call(path, print, "classExtends")]));
22
- }
23
- if (classImplements) {
24
- header.push(indent([line, call(path, print, "classImplements")]));
15
+ const { children } = path.node;
16
+ const definedClauses = definedKeys(children, [
17
+ "classExtends",
18
+ "classImplements",
19
+ "classPermits"
20
+ ]);
21
+ const hasMultipleClauses = definedClauses.length > 1;
22
+ const hasTypeParameters = children.typeParameters !== undefined;
23
+ const parts = ["class ", call(path, print, "typeIdentifier")];
24
+ if (hasTypeParameters) {
25
+ const typeParameters = call(path, print, "typeParameters");
26
+ parts.push(hasMultipleClauses ? group(indent(typeParameters)) : typeParameters);
27
+ }
28
+ if (definedClauses.length) {
29
+ const separator = hasTypeParameters && !hasMultipleClauses ? " " : line;
30
+ const clauses = definedClauses.flatMap(clause => [
31
+ separator,
32
+ call(path, print, clause)
33
+ ]);
34
+ const hasBody = children.classBody[0].children.classBodyDeclaration !== undefined;
35
+ const clauseGroup = [
36
+ hasTypeParameters && !hasMultipleClauses ? clauses : indent(clauses),
37
+ hasBody ? separator : " "
38
+ ];
39
+ parts.push(hasMultipleClauses ? clauseGroup : group(clauseGroup));
25
40
  }
26
- if (classPermits) {
27
- header.push(indent([line, call(path, print, "classPermits")]));
41
+ else {
42
+ parts.push(" ");
28
43
  }
29
- return [group(header), " ", call(path, print, "classBody")];
44
+ return [group(parts), call(path, print, "classBody")];
30
45
  },
31
46
  classModifier: printSingle,
32
47
  typeParameters(path, print) {
33
- return group([
48
+ return [
34
49
  "<",
35
50
  indent([softline, call(path, print, "typeParameterList")]),
36
51
  softline,
37
52
  ">"
38
- ]);
53
+ ];
39
54
  },
40
55
  typeParameterList(path, print) {
41
56
  return printList(path, print, "typeParameter");
@@ -51,7 +66,7 @@ export default {
51
66
  },
52
67
  classPermits: printClassPermits,
53
68
  interfaceTypeList(path, print) {
54
- return group(printList(path, print, "interfaceType"));
69
+ return printList(path, print, "interfaceType");
55
70
  },
56
71
  classBody(path, print) {
57
72
  return printBlock(path, printClassBodyDeclarations(path, print));
@@ -84,18 +99,18 @@ export default {
84
99
  : join(", ", declarators);
85
100
  },
86
101
  variableDeclarator(path, print) {
87
- var _a, _b;
102
+ var _a, _b, _c;
88
103
  const { children } = path.node;
89
104
  const variableInitializer = (_a = children.variableInitializer) === null || _a === void 0 ? void 0 : _a[0];
90
105
  const declaratorId = call(path, print, "variableDeclaratorId");
91
106
  if (!variableInitializer) {
92
107
  return declaratorId;
93
108
  }
94
- const expression = (_b = variableInitializer.children.expression) === null || _b === void 0 ? void 0 : _b[0];
109
+ const binaryExpression = (_c = (_b = variableInitializer.children.expression) === null || _b === void 0 ? void 0 : _b[0].children.conditionalExpression) === null || _c === void 0 ? void 0 : _c[0].children.binaryExpression[0];
95
110
  const declarator = [declaratorId, " ", call(path, print, "Equals")];
96
111
  const initializer = call(path, print, "variableInitializer");
97
112
  if (hasLeadingComments(variableInitializer) ||
98
- (expression && isBinaryExpression(expression))) {
113
+ (binaryExpression && hasNonAssignmentOperators(binaryExpression))) {
99
114
  declarator.push(group(indent([line, initializer])));
100
115
  }
101
116
  else {
@@ -140,7 +155,7 @@ export default {
140
155
  const { typeParameters, annotation, throws } = path.node.children;
141
156
  const header = [];
142
157
  if (typeParameters) {
143
- header.push(call(path, print, "typeParameters"));
158
+ header.push(group(call(path, print, "typeParameters")));
144
159
  }
145
160
  if (annotation) {
146
161
  header.push(join(line, map(path, print, "annotation")));
@@ -237,7 +252,7 @@ export default {
237
252
  ? indentInParentheses(join([",", line], parameters))
238
253
  : "()");
239
254
  return children.typeParameters
240
- ? [call(path, print, "typeParameters"), " ", ...header]
255
+ ? [group(call(path, print, "typeParameters")), " ", ...header]
241
256
  : header;
242
257
  },
243
258
  simpleTypeName: printSingle,
@@ -286,11 +301,18 @@ export default {
286
301
  return invocation;
287
302
  },
288
303
  enumDeclaration(path, print) {
289
- const header = ["enum", call(path, print, "typeIdentifier")];
290
- if (path.node.children.classImplements) {
291
- header.push(call(path, print, "classImplements"));
304
+ const { children } = path.node;
305
+ const parts = ["enum ", call(path, print, "typeIdentifier")];
306
+ if (children.classImplements) {
307
+ const body = children.enumBody[0].children;
308
+ const hasBody = body.enumBodyDeclarations !== undefined ||
309
+ body.enumConstantList !== undefined;
310
+ parts.push(indent([line, call(path, print, "classImplements")]), hasBody ? line : " ");
292
311
  }
293
- return join(" ", [...header, call(path, print, "enumBody")]);
312
+ else {
313
+ parts.push(" ");
314
+ }
315
+ return [group(parts), call(path, print, "enumBody")];
294
316
  },
295
317
  enumBody(path, print, options) {
296
318
  var _a;
@@ -337,19 +359,36 @@ export default {
337
359
  },
338
360
  recordDeclaration(path, print) {
339
361
  const { children } = path.node;
340
- const header = ["record ", call(path, print, "typeIdentifier")];
362
+ const parts = ["record ", call(path, print, "typeIdentifier")];
341
363
  if (children.typeParameters) {
342
- header.push(call(path, print, "typeParameters"));
364
+ parts.push(group(call(path, print, "typeParameters")));
343
365
  }
344
- header.push(call(path, print, "recordHeader"));
366
+ parts.push(call(path, print, "recordHeader"));
345
367
  if (children.classImplements) {
346
- header.push(" ", call(path, print, "classImplements"));
368
+ const hasComponents = children.recordHeader[0].children.recordComponentList !== undefined;
369
+ const hasBody = children.recordBody[0].children.recordBodyDeclaration !== undefined;
370
+ const classImplements = [
371
+ hasComponents ? " " : line,
372
+ call(path, print, "classImplements")
373
+ ];
374
+ parts.push(group([
375
+ hasComponents ? classImplements : indent(classImplements),
376
+ hasBody ? line : " "
377
+ ]));
378
+ }
379
+ else {
380
+ parts.push(" ");
347
381
  }
348
- return [group(header), " ", call(path, print, "recordBody")];
382
+ return [group(parts), call(path, print, "recordBody")];
349
383
  },
350
384
  recordHeader(path, print) {
351
385
  return path.node.children.recordComponentList
352
- ? indentInParentheses(call(path, print, "recordComponentList"))
386
+ ? [
387
+ "(",
388
+ indent([softline, call(path, print, "recordComponentList")]),
389
+ softline,
390
+ ")"
391
+ ]
353
392
  : indentInParentheses(printDanglingComments(path), { shouldBreak: true });
354
393
  },
355
394
  recordComponentList(path, print) {
@@ -1,4 +1,4 @@
1
- import type { StringTemplateCstNode, TextBlockTemplateCstNode } from "java-parser";
1
+ import type { BinaryExpressionCstNode, PrimaryCstNode, StringTemplateCstNode, TextBlockTemplateCstNode } from "java-parser";
2
2
  import type { AstPath } from "prettier";
3
3
  import { builders } from "prettier/doc";
4
4
  import type { JavaComment } from "../comments.js";
@@ -31,7 +31,7 @@ declare const _default: {
31
31
  conditionalExpression(path: AstPath<import("java-parser").ConditionalExpressionCstNode & {
32
32
  comments?: JavaComment[];
33
33
  }>, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc;
34
- binaryExpression(path: AstPath<import("java-parser").BinaryExpressionCstNode & {
34
+ binaryExpression(path: AstPath<BinaryExpressionCstNode & {
35
35
  comments?: JavaComment[];
36
36
  }>, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc;
37
37
  unaryExpression(path: AstPath<import("java-parser").UnaryExpressionCstNode & {
@@ -40,7 +40,7 @@ declare const _default: {
40
40
  unaryExpressionNotPlusMinus(path: AstPath<import("java-parser").UnaryExpressionNotPlusMinusCstNode & {
41
41
  comments?: JavaComment[];
42
42
  }>, print: JavaPrintFn): builders.Doc[];
43
- primary(path: AstPath<import("java-parser").PrimaryCstNode & {
43
+ primary(path: AstPath<PrimaryCstNode & {
44
44
  comments?: JavaComment[];
45
45
  }>, print: JavaPrintFn): builders.Doc;
46
46
  primaryPrefix: typeof printSingle;
@@ -61,7 +61,7 @@ declare const _default: {
61
61
  }>, print: JavaPrintFn): builders.Doc;
62
62
  parenthesisExpression(path: AstPath<import("java-parser").ParenthesisExpressionCstNode & {
63
63
  comments?: JavaComment[];
64
- }>, print: JavaPrintFn): builders.Group | "()" | (string | builders.Indent)[];
64
+ }>, print: JavaPrintFn): builders.Group | "()";
65
65
  castExpression: typeof printSingle;
66
66
  primitiveCastExpression(path: AstPath<import("java-parser").PrimitiveCastExpressionCstNode & {
67
67
  comments?: JavaComment[];
@@ -1,5 +1,5 @@
1
1
  import { builders, utils } from "prettier/doc";
2
- import { call, definedKeys, each, findBaseIndent, flatMap, hasLeadingComments, indentInParentheses, isBinaryExpression, isNonTerminal, isTerminal, map, onlyDefinedKey, printDanglingComments, printList, printName, printSingle } from "./helpers.js";
2
+ import { call, definedKeys, each, findBaseIndent, flatMap, hasAssignmentOperators, hasLeadingComments, hasNonAssignmentOperators, indentInParentheses, isNonTerminal, isTerminal, map, onlyDefinedKey, printDanglingComments, printList, printName, printSingle } from "./helpers.js";
3
3
  const { align, breakParent, conditionalGroup, group, hardline, ifBreak, indent, indentIfBreak, join, line, lineSuffixBoundary, softline } = builders;
4
4
  const { removeLines, willBreak } = utils;
5
5
  export default {
@@ -64,26 +64,30 @@ export default {
64
64
  conditionalExpression(path, print, options) {
65
65
  var _a;
66
66
  const binaryExpression = call(path, print, "binaryExpression");
67
+ const grandparentNodeName = (_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name;
68
+ const isInParentheses = grandparentNodeName === "parenthesisExpression";
67
69
  if (!path.node.children.QuestionMark) {
68
- return binaryExpression;
70
+ return isInParentheses ? binaryExpression : group(binaryExpression);
69
71
  }
70
72
  const [consequent, alternate] = map(path, print, "expression");
71
- const parts = [binaryExpression];
72
- const part = [
73
+ const suffix = [
73
74
  line,
74
75
  ["? ", options.useTabs ? indent(consequent) : align(2, consequent)],
75
76
  line,
76
77
  [": ", options.useTabs ? indent(alternate) : align(2, alternate)]
77
78
  ];
78
- const isNestedTernary = ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) ===
79
- "conditionalExpression";
80
- parts.push(!isNestedTernary || options.useTabs
81
- ? part
82
- : align(Math.max(0, options.tabWidth - 2), part));
83
- return isNestedTernary ? parts : group(indent(parts));
79
+ const isNestedTernary = grandparentNodeName === "conditionalExpression";
80
+ const alignedSuffix = !isNestedTernary || options.useTabs
81
+ ? suffix
82
+ : align(Math.max(0, options.tabWidth - 2), suffix);
83
+ if (isNestedTernary) {
84
+ return [group(binaryExpression), alignedSuffix];
85
+ }
86
+ const parts = [group(binaryExpression), indent(alignedSuffix)];
87
+ return isInParentheses ? parts : group(parts);
84
88
  },
85
89
  binaryExpression(path, print, options) {
86
- var _a, _b;
90
+ var _a, _b, _c, _d;
87
91
  const { children } = path.node;
88
92
  const operands = flatMap(path, print, definedKeys(children, [
89
93
  "expression",
@@ -110,13 +114,12 @@ export default {
110
114
  "Instanceof",
111
115
  "shiftOperator"
112
116
  ]));
113
- const hasNonAssignmentOperators = (operators.length > 0 && !children.AssignmentOperator) ||
114
- (children.expression !== undefined &&
115
- isBinaryExpression(children.expression[0]));
116
117
  const isInList = ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) === "elementValue" ||
117
118
  ((_b = path.getNode(6)) === null || _b === void 0 ? void 0 : _b.name) === "argumentList";
119
+ const binaryExpression = (_d = (_c = children.expression) === null || _c === void 0 ? void 0 : _c[0].children.conditionalExpression) === null || _d === void 0 ? void 0 : _d[0].children.binaryExpression[0];
118
120
  return binary(operands, operators, {
119
- hasNonAssignmentOperators,
121
+ hasNonAssignmentOperators: (operators.length > 0 && !children.AssignmentOperator) ||
122
+ (binaryExpression && hasNonAssignmentOperators(binaryExpression)),
120
123
  isInList,
121
124
  isRoot: true,
122
125
  operatorPosition: options.experimentalOperatorPosition
@@ -265,17 +268,36 @@ export default {
265
268
  : keyword;
266
269
  },
267
270
  parenthesisExpression(path, print) {
268
- var _a;
269
271
  const expression = call(path, print, "expression");
270
- const ancestorName = (_a = path.getNode(14)) === null || _a === void 0 ? void 0 : _a.name;
271
- const binaryExpression = path.getNode(8);
272
- return ancestorName &&
273
- ["guard", "returnStatement"].includes(ancestorName) &&
274
- binaryExpression &&
275
- binaryExpression.name === "binaryExpression" &&
276
- Object.keys(binaryExpression.children).length === 1
277
- ? indentInParentheses(expression)
278
- : ["(", indent(expression), ")"];
272
+ const primaryAncestor = path.getNode(4);
273
+ const binaryExpressionAncestor = path.getNode(8);
274
+ const outerAncestor = path.getNode(14);
275
+ const { conditionalExpression, lambdaExpression } = path.node.children.expression[0].children;
276
+ const hasLambda = lambdaExpression !== undefined;
277
+ const hasTernary = (conditionalExpression === null || conditionalExpression === void 0 ? void 0 : conditionalExpression[0].children.QuestionMark) !== undefined;
278
+ const hasSuffix = (primaryAncestor === null || primaryAncestor === void 0 ? void 0 : primaryAncestor.children.primarySuffix) !== undefined;
279
+ const isAssignment = ((outerAncestor === null || outerAncestor === void 0 ? void 0 : outerAncestor.name) === "binaryExpression" &&
280
+ hasAssignmentOperators(outerAncestor)) ||
281
+ (outerAncestor === null || outerAncestor === void 0 ? void 0 : outerAncestor.name) === "variableInitializer";
282
+ if (!hasLambda && hasSuffix && (!hasTernary || isAssignment)) {
283
+ return indentInParentheses(hasTernary ? group(expression) : expression);
284
+ }
285
+ else if (binaryExpressionAncestor &&
286
+ Object.keys(binaryExpressionAncestor.children).length === 1 &&
287
+ outerAncestor &&
288
+ ["guard", "returnStatement"].includes(outerAncestor.name)) {
289
+ return indentInParentheses(group(expression));
290
+ }
291
+ else if (hasTernary && hasSuffix && !isAssignment) {
292
+ return group(["(", expression, softline, ")"]);
293
+ }
294
+ else {
295
+ return group([
296
+ "(",
297
+ hasLambda || hasTernary ? expression : indent(expression),
298
+ ")"
299
+ ]);
300
+ }
279
301
  },
280
302
  castExpression: printSingle,
281
303
  primitiveCastExpression(path, print) {
@@ -507,8 +529,8 @@ function binary(operands, operators, { hasNonAssignmentOperators = false, isInLi
507
529
  const content = binary(operands, operators, { operatorPosition });
508
530
  operands.unshift(levelOperator !== undefined &&
509
531
  needsParentheses(nextOperator, levelOperator)
510
- ? ["(", indent(content), ")"]
511
- : content);
532
+ ? ["(", group(indent(content)), ")"]
533
+ : group(content));
512
534
  }
513
535
  }
514
536
  level.push(operands.shift());
@@ -516,17 +538,17 @@ function binary(operands, operators, { hasNonAssignmentOperators = false, isInLi
516
538
  (!isInList &&
517
539
  !isAssignmentOperator(levelOperator) &&
518
540
  levelOperator !== "instanceof")) {
519
- return group(level);
541
+ return level;
520
542
  }
521
543
  if (!isRoot || hasNonAssignmentOperators) {
522
- return group(indent(level));
544
+ return indent(level);
523
545
  }
524
546
  const groupId = Symbol("assignment");
525
- return group([
547
+ return [
526
548
  level[0],
527
549
  group(indent(level[1]), { id: groupId }),
528
550
  indentIfBreak(level[2], { groupId })
529
- ]);
551
+ ];
530
552
  }
531
553
  const precedencesByOperator = new Map([
532
554
  ["||"],
@@ -1,4 +1,4 @@
1
- import type { AnnotationCstNode, ClassPermitsCstNode, ClassTypeCtx, CstElement, CstNode, ExpressionCstNode, InterfacePermitsCstNode, IToken, StatementCstNode } from "java-parser";
1
+ import type { AnnotationCstNode, BinaryExpressionCstNode, ClassPermitsCstNode, ClassTypeCtx, CstElement, CstNode, ExpressionCstNode, InterfacePermitsCstNode, IToken, StatementCstNode } from "java-parser";
2
2
  import type { AstPath, Doc, ParserOptions } from "prettier";
3
3
  import { builders } from "prettier/doc";
4
4
  import type { JavaComment } from "../comments.js";
@@ -32,6 +32,8 @@ export declare function printClassType(path: AstPath<JavaNonTerminal & {
32
32
  children: ClassTypeCtx;
33
33
  }>, print: JavaPrintFn): builders.Doc[];
34
34
  export declare function isBinaryExpression(expression: ExpressionCstNode): boolean;
35
+ export declare function hasAssignmentOperators(binaryExpression: BinaryExpressionCstNode): boolean;
36
+ export declare function hasNonAssignmentOperators(binaryExpression: BinaryExpressionCstNode): boolean;
35
37
  export declare function findBaseIndent(lines: string[]): number;
36
38
  export declare function isEmptyStatement(statement: StatementCstNode): boolean;
37
39
  export declare function isNonTerminal(node: CstElement): node is JavaNonTerminal;
@@ -157,18 +157,52 @@ export function printArrayInitializer(path, print, options, child) {
157
157
  return list.length ? group(["{", indent([line, ...list]), line, "}"]) : "{}";
158
158
  }
159
159
  export function printBlock(path, contents) {
160
- if (!contents.length) {
161
- const danglingComments = printDanglingComments(path);
162
- return danglingComments.length
163
- ? ["{", indent([hardline, ...danglingComments]), hardline, "}"]
164
- : "{}";
160
+ if (contents.length) {
161
+ return group([
162
+ "{",
163
+ indent([hardline, ...join(hardline, contents)]),
164
+ hardline,
165
+ "}"
166
+ ]);
165
167
  }
166
- return group([
167
- "{",
168
- indent([hardline, ...join(hardline, contents)]),
169
- hardline,
170
- "}"
171
- ]);
168
+ const danglingComments = printDanglingComments(path);
169
+ if (danglingComments.length) {
170
+ return ["{", indent([hardline, ...danglingComments]), hardline, "}"];
171
+ }
172
+ const parent = path.grandparent;
173
+ const grandparent = path.getNode(4);
174
+ const greatGrandparent = path.getNode(6);
175
+ return ((grandparent === null || grandparent === void 0 ? void 0 : grandparent.name) === "catches" &&
176
+ grandparent.children.catchClause.length === 1 &&
177
+ ((greatGrandparent === null || greatGrandparent === void 0 ? void 0 : greatGrandparent.name) === "tryStatement" ||
178
+ (greatGrandparent === null || greatGrandparent === void 0 ? void 0 : greatGrandparent.name) === "tryWithResourcesStatement") &&
179
+ !greatGrandparent.children.finally) ||
180
+ (greatGrandparent &&
181
+ [
182
+ "basicForStatement",
183
+ "doStatement",
184
+ "enhancedForStatement",
185
+ "whileStatement"
186
+ ].includes(greatGrandparent.name)) ||
187
+ [
188
+ "annotationInterfaceBody",
189
+ "classBody",
190
+ "constructorBody",
191
+ "enumBody",
192
+ "interfaceBody",
193
+ "moduleDeclaration",
194
+ "recordBody"
195
+ ].includes(path.node.name) ||
196
+ (parent &&
197
+ [
198
+ "instanceInitializer",
199
+ "lambdaBody",
200
+ "methodBody",
201
+ "staticInitializer",
202
+ "synchronizedStatement"
203
+ ].includes(parent.name))
204
+ ? "{}"
205
+ : ["{", hardline, "}"];
172
206
  }
173
207
  export function printName(path, print) {
174
208
  return join(".", map(path, print, "Identifier"));
@@ -177,10 +211,7 @@ export function printList(path, print, child) {
177
211
  return join([",", line], map(path, print, child));
178
212
  }
179
213
  export function printClassPermits(path, print) {
180
- return group([
181
- "permits",
182
- indent([line, group(printList(path, print, "typeName"))])
183
- ]);
214
+ return group(["permits", indent([line, printList(path, print, "typeName")])]);
184
215
  }
185
216
  export function printClassType(path, print) {
186
217
  const { children } = path.node;
@@ -217,12 +248,13 @@ export function isBinaryExpression(expression) {
217
248
  if (isTernary) {
218
249
  return false;
219
250
  }
220
- const hasNonAssignmentOperators = Object.values(conditionalExpression.binaryExpression[0].children).some(child => {
221
- var _a;
222
- return isTerminal(child[0]) &&
223
- !((_a = child[0].tokenType.CATEGORIES) === null || _a === void 0 ? void 0 : _a.some(category => category.name === "AssignmentOperator"));
224
- });
225
- return hasNonAssignmentOperators;
251
+ return hasNonAssignmentOperators(conditionalExpression.binaryExpression[0]);
252
+ }
253
+ export function hasAssignmentOperators(binaryExpression) {
254
+ return binaryExpression.children.AssignmentOperator !== undefined;
255
+ }
256
+ export function hasNonAssignmentOperators(binaryExpression) {
257
+ return Object.keys(binaryExpression.children).some(name => ["BinaryOperator", "Instanceof", "shiftOperator"].includes(name));
226
258
  }
227
259
  export function findBaseIndent(lines) {
228
260
  return lines.length
@@ -1,5 +1,5 @@
1
1
  import { builders } from "prettier/doc";
2
- import { call, each, hasDeclarationAnnotations, indentInParentheses, lineEndWithComments, lineStartWithComments, onlyDefinedKey, printArrayInitializer, printBlock, printClassPermits, printList, printSingle, printWithModifiers } from "./helpers.js";
2
+ import { call, definedKeys, each, hasDeclarationAnnotations, indentInParentheses, lineEndWithComments, lineStartWithComments, onlyDefinedKey, printArrayInitializer, printBlock, printClassPermits, printList, printSingle, printWithModifiers } from "./helpers.js";
3
3
  const { group, hardline, indent, join, line } = builders;
4
4
  export default {
5
5
  interfaceDeclaration(path, print) {
@@ -10,18 +10,36 @@ export default {
10
10
  return printWithModifiers(path, print, "interfaceModifier", call(path, print, declarationKey), true);
11
11
  },
12
12
  normalInterfaceDeclaration(path, print) {
13
- const { interfaceExtends, interfacePermits, typeParameters } = path.node.children;
14
- const header = ["interface ", call(path, print, "typeIdentifier")];
15
- if (typeParameters) {
16
- header.push(call(path, print, "typeParameters"));
13
+ const { children } = path.node;
14
+ const definedClauses = definedKeys(children, [
15
+ "interfaceExtends",
16
+ "interfacePermits"
17
+ ]);
18
+ const hasMultipleClauses = definedClauses.length > 1;
19
+ const hasTypeParameters = children.typeParameters !== undefined;
20
+ const parts = ["interface ", call(path, print, "typeIdentifier")];
21
+ if (hasTypeParameters) {
22
+ const typeParameters = call(path, print, "typeParameters");
23
+ parts.push(hasMultipleClauses ? group(indent(typeParameters)) : typeParameters);
17
24
  }
18
- if (interfaceExtends) {
19
- header.push(indent([line, call(path, print, "interfaceExtends")]));
25
+ if (definedClauses.length) {
26
+ const separator = hasTypeParameters && !hasMultipleClauses ? " " : line;
27
+ const clauses = definedClauses.flatMap(clause => [
28
+ separator,
29
+ call(path, print, clause)
30
+ ]);
31
+ const hasBody = children.interfaceBody[0].children.interfaceMemberDeclaration !==
32
+ undefined;
33
+ const clauseGroup = [
34
+ hasTypeParameters && !hasMultipleClauses ? clauses : indent(clauses),
35
+ hasBody ? separator : " "
36
+ ];
37
+ parts.push(hasMultipleClauses ? clauseGroup : group(clauseGroup));
20
38
  }
21
- if (interfacePermits) {
22
- header.push(indent([line, call(path, print, "interfacePermits")]));
39
+ else {
40
+ parts.push(" ");
23
41
  }
24
- return [group(header), " ", call(path, print, "interfaceBody")];
42
+ return [group(parts), call(path, print, "interfaceBody")];
25
43
  },
26
44
  interfaceModifier: printSingle,
27
45
  interfaceExtends(path, print) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prettier-plugin-java",
3
- "version": "2.7.6",
3
+ "version": "2.8.0",
4
4
  "description": "Prettier Java Plugin",
5
5
  "type": "module",
6
6
  "exports": {
@@ -41,5 +41,5 @@
41
41
  "peerDependencies": {
42
42
  "prettier": "^3.0.0"
43
43
  },
44
- "gitHead": "9f2ba5e304a7e2d744fa20f1f3617cc4a4651f88"
44
+ "gitHead": "9204b4f91e2320e7bddff9fb21c1a85fd4fb9e9a"
45
45
  }