Skip to content

Commit 37029a5

Browse files
committed
Matching Prettier's binary operation grouping and indentation
1 parent eb33176 commit 37029a5

File tree

12 files changed

+169
-140
lines changed

12 files changed

+169
-140
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { defaultBinaryOperationPrinter } from './printers/create-binary-operation-printer.js';
2+
3+
export const addition = {
4+
match: (op) => ['+', '-'].includes(op),
5+
print: defaultBinaryOperationPrinter
6+
// grouping and indenting before `bit` and `shift` should technically be here
7+
// but they are properly parenthesised before reaching this point.
8+
};

src/binary-operator-printers/arithmetic.js

Lines changed: 0 additions & 51 deletions
This file was deleted.

src/binary-operator-printers/bit.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { arithmetic } from './arithmetic.js';
1+
import { defaultBinaryOperationPrinter } from './printers/create-binary-operation-printer.js';
22

33
export const bit = {
44
match: (op) => ['&', '|', '^'].includes(op),
5-
print: arithmetic.print
5+
print: defaultBinaryOperationPrinter
66
};
Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
import { doc } from 'prettier';
2+
import {
3+
createBinaryOperationPrinter,
4+
createIndentIfNecessaryBuilder
5+
} from './printers/create-binary-operation-printer.js';
6+
import { addition } from './addition.js';
7+
import { multiplication } from './multiplication.js';
28

3-
const { group, indent, line } = doc.builders;
9+
const { group } = doc.builders;
10+
11+
const exponentiationPrinter = createBinaryOperationPrinter(
12+
() => (document) => group(document), // always group
13+
createIndentIfNecessaryBuilder([
14+
addition,
15+
multiplication
16+
// `bit` and `shift` should technically be here but they are properly
17+
// parenthesised before reaching this point.
18+
])
19+
);
420

521
export const exponentiation = {
622
match: (op) => op === '**',
7-
print: (node, path, print) => {
8-
const right = [' ', node.operator, line, path.call(print, 'right')];
9-
// If it's a single binary operation, avoid having a small right
10-
// operand like - 1 on its own line
11-
const shouldGroup =
12-
node.left.type !== 'BinaryOperation' &&
13-
path.getParentNode().type !== 'BinaryOperation';
14-
return group([
15-
path.call(print, 'left'),
16-
indent(shouldGroup ? group(right) : right)
17-
]);
18-
}
23+
print: exponentiationPrinter
1924
};

src/binary-operator-printers/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
export * from './arithmetic.js';
1+
export * from './addition.js';
22
export * from './assignment.js';
33
export * from './bit.js';
44
export * from './comparison.js';
55
export * from './exponentiation.js';
66
export * from './logical.js';
7+
export * from './multiplication.js';
78
export * from './shift.js';
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {
2+
createBinaryOperationPrinter,
3+
createGroupIfNecessaryBuilder,
4+
createIndentIfNecessaryBuilder
5+
} from './printers/create-binary-operation-printer.js';
6+
import { addition } from './addition.js';
7+
import { bit } from './bit.js';
8+
import { shift } from './shift.js';
9+
10+
const matchers = [addition, bit, shift];
11+
12+
const multiplicationPrinter = createBinaryOperationPrinter(
13+
createGroupIfNecessaryBuilder(matchers),
14+
createIndentIfNecessaryBuilder(matchers)
15+
);
16+
17+
export const multiplication = {
18+
match: (op) => ['*', '/', '%'].includes(op),
19+
print: multiplicationPrinter
20+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { doc } from 'prettier';
2+
import { assignment } from '../assignment.js';
3+
import { comparison } from '../comparison.js';
4+
5+
const { group, indent, line } = doc.builders;
6+
7+
const shouldGroupOrIndent = (node, matchers) =>
8+
matchers.some((matcher) => matcher.match(node.operator));
9+
10+
export const createGroupIfNecessaryBuilder =
11+
(matchers) => (path) => (document) => {
12+
const parentNode = path.getParentNode();
13+
if (
14+
parentNode.type === 'BinaryOperation' &&
15+
!comparison.match(parentNode.operator)
16+
) {
17+
return shouldGroupOrIndent(parentNode, matchers)
18+
? group(document)
19+
: document;
20+
}
21+
return group(document);
22+
};
23+
24+
export const createIndentIfNecessaryBuilder =
25+
(matchers) => (path) => (document) => {
26+
let node = path.getNode();
27+
for (let i = 0; ; i += 1) {
28+
const parentNode = path.getParentNode(i);
29+
if (parentNode.type === 'ReturnStatement') return document;
30+
if (
31+
parentNode.type !== 'BinaryOperation' ||
32+
comparison.match(parentNode.operator) ||
33+
shouldGroupOrIndent(parentNode, matchers)
34+
) {
35+
return indent(document);
36+
}
37+
if (node === parentNode.right) return document;
38+
node = parentNode;
39+
}
40+
};
41+
42+
export const createBinaryOperationPrinter =
43+
(groupIfNecessaryBuilder, indentIfNecessaryBuilder) =>
44+
(node, path, print) => {
45+
const groupIfNecessary = groupIfNecessaryBuilder(path);
46+
const indentIfNecessary = indentIfNecessaryBuilder(path);
47+
48+
const right = [' ', node.operator, line, path.call(print, 'right')];
49+
// If it's a single binary operation, avoid having a small right
50+
// operand like - 1 on its own line
51+
const parent = path.getParentNode();
52+
const shouldGroup =
53+
node.left.type !== 'BinaryOperation' &&
54+
(parent.type !== 'BinaryOperation' || assignment.match(parent.operator));
55+
return groupIfNecessary([
56+
path.call(print, 'left'),
57+
indentIfNecessary(shouldGroup ? group(right) : right)
58+
]);
59+
};
60+
61+
export const defaultBinaryOperationPrinter = createBinaryOperationPrinter(
62+
createGroupIfNecessaryBuilder([]),
63+
createIndentIfNecessaryBuilder([])
64+
);

src/binary-operator-printers/shift.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { arithmetic } from './arithmetic.js';
1+
import { defaultBinaryOperationPrinter } from './printers/create-binary-operation-printer.js';
22

33
export const shift = {
44
match: (op) => ['<<', '>>'].includes(op),
5-
print: arithmetic.print
5+
print: defaultBinaryOperationPrinter
6+
// grouping and indenting before `bit` should technically be here but they
7+
// are properly parenthesised before reaching this point.
68
};

0 commit comments

Comments
 (0)