prettier 0.12.2 → 0.12.3

Sign up to get free protection for your applications and to get access to all the features.
data/src/nodes/alias.js CHANGED
@@ -1,4 +1,4 @@
1
- const { concat, join } = require("../builders");
1
+ const { concat, join } = require("../prettier");
2
2
 
3
3
  const usingSymbols = path => {
4
4
  const [left, right] = path.getValue().body.map(node => node.body[0].type);
data/src/nodes/args.js ADDED
@@ -0,0 +1,88 @@
1
+ const {
2
+ concat,
3
+ group,
4
+ ifBreak,
5
+ indent,
6
+ join,
7
+ line,
8
+ softline
9
+ } = require("../prettier");
10
+
11
+ const toProc = require("../toProc");
12
+ const { makeArgs } = require("../utils");
13
+
14
+ module.exports = {
15
+ arg_paren: (path, opts, print) => {
16
+ if (path.getValue().body[0] === null) {
17
+ return "";
18
+ }
19
+
20
+ const { addTrailingCommas } = opts;
21
+ const { args, heredocs } = makeArgs(path, opts, print, 0);
22
+
23
+ const argsNode = path.getValue().body[0];
24
+ const hasBlock = argsNode.type === "args_add_block" && argsNode.body[1];
25
+
26
+ if (heredocs.length > 1) {
27
+ return concat(["(", join(", ", args), ")"].concat(heredocs));
28
+ }
29
+
30
+ const parenDoc = group(
31
+ concat([
32
+ "(",
33
+ indent(
34
+ concat([
35
+ softline,
36
+ join(concat([",", line]), args),
37
+ addTrailingCommas && !hasBlock ? ifBreak(",", "") : ""
38
+ ])
39
+ ),
40
+ concat([softline, ")"])
41
+ ])
42
+ );
43
+
44
+ if (heredocs.length === 1) {
45
+ return group(concat([parenDoc].concat(heredocs)));
46
+ }
47
+
48
+ return parenDoc;
49
+ },
50
+ args: (path, opts, print) => {
51
+ const args = path.map(print, "body");
52
+ let blockNode = null;
53
+
54
+ [1, 2, 3].find(parent => {
55
+ const parentNode = path.getParentNode(parent);
56
+ blockNode =
57
+ parentNode &&
58
+ parentNode.type === "method_add_block" &&
59
+ parentNode.body[1];
60
+ return blockNode;
61
+ });
62
+
63
+ const proc = blockNode && toProc(blockNode);
64
+ if (proc) {
65
+ args.push(proc);
66
+ }
67
+
68
+ return args;
69
+ },
70
+ args_add_block: (path, opts, print) => {
71
+ const parts = path.call(print, "body", 0);
72
+
73
+ if (path.getValue().body[1]) {
74
+ parts.push(concat(["&", path.call(print, "body", 1)]));
75
+ }
76
+
77
+ return parts;
78
+ },
79
+ args_add_star: (path, opts, print) => {
80
+ const printed = path.map(print, "body");
81
+ const parts = printed[0]
82
+ .concat([concat(["*", printed[1]])])
83
+ .concat(printed.slice(2));
84
+
85
+ return parts;
86
+ },
87
+ blockarg: (path, opts, print) => concat(["&", path.call(print, "body", 0)])
88
+ };
data/src/nodes/arrays.js CHANGED
@@ -7,7 +7,7 @@ const {
7
7
  line,
8
8
  literalline,
9
9
  softline
10
- } = require("../builders");
10
+ } = require("../prettier");
11
11
 
12
12
  const isStringArray = args =>
13
13
  args.body.every(
@@ -0,0 +1,39 @@
1
+ const { concat, group, indent, join, line } = require("../prettier");
2
+ const { concatBody, first, skipAssignIndent } = require("../utils");
3
+
4
+ module.exports = {
5
+ assign: (path, opts, print) => {
6
+ const [printedTarget, printedValue] = path.map(print, "body");
7
+ let adjustedValue = printedValue;
8
+
9
+ if (
10
+ ["mrhs_add_star", "mrhs_new_from_args"].includes(
11
+ path.getValue().body[1].type
12
+ )
13
+ ) {
14
+ adjustedValue = group(join(concat([",", line]), printedValue));
15
+ }
16
+
17
+ if (skipAssignIndent(path.getValue().body[1])) {
18
+ return group(concat([printedTarget, " = ", adjustedValue]));
19
+ }
20
+
21
+ return group(
22
+ concat([printedTarget, " =", indent(concat([line, adjustedValue]))])
23
+ );
24
+ },
25
+ assign_error: (_path, _opts, _print) => {
26
+ throw new Error("Can't set variable");
27
+ },
28
+ opassign: (path, opts, print) =>
29
+ group(
30
+ concat([
31
+ path.call(print, "body", 0),
32
+ " ",
33
+ path.call(print, "body", 1),
34
+ indent(concat([line, path.call(print, "body", 2)]))
35
+ ])
36
+ ),
37
+ var_field: concatBody,
38
+ var_ref: first
39
+ };
data/src/nodes/blocks.js CHANGED
@@ -4,9 +4,11 @@ const {
4
4
  group,
5
5
  ifBreak,
6
6
  indent,
7
+ join,
8
+ removeLines,
7
9
  softline
8
- } = require("../builders");
9
- const { hasAncestor } = require("../utils");
10
+ } = require("../prettier");
11
+ const { empty, first, hasAncestor } = require("../utils");
10
12
 
11
13
  const printBlock = (path, opts, print) => {
12
14
  const [variables, statements] = path.getValue().body;
@@ -61,6 +63,19 @@ const printBlock = (path, opts, print) => {
61
63
  };
62
64
 
63
65
  module.exports = {
66
+ block_var: (path, opts, print) => {
67
+ const parts = ["|", removeLines(path.call(print, "body", 0))];
68
+
69
+ // The second part of this node is a list of optional block-local variables
70
+ if (path.getValue().body[1]) {
71
+ parts.push("; ", join(", ", path.map(print, "body", 1)));
72
+ }
73
+
74
+ parts.push("| ");
75
+ return concat(parts);
76
+ },
64
77
  brace_block: printBlock,
65
- do_block: printBlock
78
+ do_block: printBlock,
79
+ excessed_comma: empty,
80
+ number_arg: first
66
81
  };
data/src/nodes/calls.js CHANGED
@@ -1,5 +1,6 @@
1
- const { concat, group, indent, softline } = require("../builders");
2
- const { makeCall } = require("../utils");
1
+ const { concat, group, indent, softline } = require("../prettier");
2
+ const toProc = require("../toProc");
3
+ const { concatBody, first, makeCall } = require("../utils");
3
4
 
4
5
  const noIndent = ["array", "hash", "method_add_block", "xstring_literal"];
5
6
 
@@ -24,5 +25,38 @@ module.exports = {
24
25
  return group(
25
26
  concat([receiver, indent(concat([softline, operator, name]))])
26
27
  );
27
- }
28
+ },
29
+ fcall: concatBody,
30
+ method_add_arg: (path, opts, print) => {
31
+ const [method, args] = path.map(print, "body");
32
+ const argNode = path.getValue().body[1];
33
+
34
+ // This case will ONLY be hit if we can successfully turn the block into a
35
+ // to_proc call. In that case, we just explicitly add the parens around it.
36
+ if (argNode.type === "args" && args.length > 0) {
37
+ return concat([method, "("].concat(args).concat(")"));
38
+ }
39
+
40
+ return concat([method, args]);
41
+ },
42
+ method_add_block: (path, opts, print) => {
43
+ const [method, block] = path.getValue().body;
44
+ const proc = toProc(block);
45
+
46
+ if (proc && method.type === "call") {
47
+ return group(
48
+ concat([
49
+ path.call(print, "body", 0),
50
+ "(",
51
+ indent(concat([softline, proc])),
52
+ concat([softline, ")"])
53
+ ])
54
+ );
55
+ }
56
+ if (proc) {
57
+ return path.call(print, "body", 0);
58
+ }
59
+ return concat(path.map(print, "body"));
60
+ },
61
+ vcall: first
28
62
  };
data/src/nodes/case.js CHANGED
@@ -6,7 +6,7 @@ const {
6
6
  hardline,
7
7
  indent,
8
8
  line
9
- } = require("../builders");
9
+ } = require("../prettier");
10
10
 
11
11
  module.exports = {
12
12
  case: (path, opts, print) => {
@@ -1,9 +1,10 @@
1
- const { align, concat, group, ifBreak, join, line } = require("../builders");
1
+ const { align, concat, group, ifBreak, join, line } = require("../prettier");
2
2
  const { docLength, makeArgs, makeCall } = require("../utils");
3
3
 
4
4
  const hasDef = node =>
5
5
  node.body[1].type === "args_add_block" &&
6
6
  node.body[1].body[0].type === "args" &&
7
+ node.body[1].body[0].body[0] &&
7
8
  node.body[1].body[0].body[0].type === "def";
8
9
 
9
10
  module.exports = {
@@ -7,7 +7,7 @@ const {
7
7
  ifBreak,
8
8
  indent,
9
9
  softline
10
- } = require("../builders");
10
+ } = require("../prettier");
11
11
 
12
12
  const noTernary = [
13
13
  "@comment",
@@ -47,49 +47,114 @@ const printWithAddition = (keyword, path, print, { breaking = false } = {}) =>
47
47
  breaking ? breakParent : ""
48
48
  ]);
49
49
 
50
- const printTernaryConditions = (keyword, truthyValue, falsyValue) => {
51
- const parts = [truthyValue, " : ", falsyValue];
50
+ // For the unary `not` operator, we need to explicitly add parentheses to it in
51
+ // order for it to be valid from within a ternary. Otherwise if the clause of
52
+ // the ternary isn't a unary `not`, we can just pass it along.
53
+ const printTernaryClause = clause => {
54
+ if (clause.type === "concat") {
55
+ const [part] = clause.parts;
56
+
57
+ if (part.type === "concat" && part.parts[0] === "not") {
58
+ // We are inside of a statements list and the statement is a unary `not`.
59
+ return concat(["not(", part.parts[2], ")"]);
60
+ }
61
+
62
+ if (clause.parts[0] === "not") {
63
+ // We are inside a ternary condition and the clause is a unary `not`.
64
+ return concat(["not(", clause.parts[2], ")"]);
65
+ }
66
+ }
67
+
68
+ return clause;
69
+ };
70
+
71
+ // The conditions for a ternary look like `foo : bar` where `foo` represents
72
+ // the truthy clause and `bar` represents the falsy clause. In the case that the
73
+ // parent node is an `unless`, these have to flip in order.
74
+ const printTernaryClauses = (keyword, truthyClause, falsyClause) => {
75
+ const parts = [
76
+ printTernaryClause(truthyClause),
77
+ " : ",
78
+ printTernaryClause(falsyClause)
79
+ ];
80
+
52
81
  return keyword === "if" ? parts : parts.reverse();
53
82
  };
54
83
 
55
- const canTernary = stmts =>
56
- stmts.body.length === 1 && !noTernary.includes(stmts.body[0].type);
84
+ // Handles ternary nodes. If it does not fit on one line, then we break out into
85
+ // an if/else statement. Otherwise we remain as a ternary.
86
+ const printTernary = (path, _opts, print) => {
87
+ const [predicate, truthyClause, falsyClause] = path.map(print, "body");
88
+ const ternaryClauses = printTernaryClauses("if", truthyClause, falsyClause);
57
89
 
58
- const printConditional = keyword => (path, { inlineConditionals }, print) => {
59
- const [_predicate, stmts, addition] = path.getValue().body;
90
+ return group(
91
+ ifBreak(
92
+ concat([
93
+ "if ",
94
+ predicate,
95
+ indent(concat([softline, truthyClause])),
96
+ concat([softline, "else"]),
97
+ indent(concat([softline, falsyClause])),
98
+ concat([softline, "end"])
99
+ ]),
100
+ concat([predicate, " ? "].concat(ternaryClauses))
101
+ )
102
+ );
103
+ };
60
104
 
61
- // If the addition is not an elsif or an else, then it's the second half of a
62
- // ternary expression
63
- if (addition && addition.type !== "elsif" && addition.type !== "else") {
64
- const parts = [path.call(print, "body", 0), " ? "];
65
- const truthyValue = path.call(print, "body", 1);
66
- const falsyValue = path.call(print, "body", 2);
105
+ // Prints an `if_mod` or `unless_mod` node. Because it was previously in the
106
+ // modifier form, we're guaranteed to not have an additional node, so we can
107
+ // just work with the predicate and the body.
108
+ const printSingle = keyword => (path, { inlineConditionals }, print) => {
109
+ const multiline = concat([
110
+ `${keyword} `,
111
+ align(keyword.length - 1, path.call(print, "body", 0)),
112
+ indent(concat([softline, path.call(print, "body", 1)])),
113
+ concat([softline, "end"])
114
+ ]);
67
115
 
68
- return group(
69
- ifBreak(
70
- concat([
71
- `${keyword} `,
72
- path.call(print, "body", 0),
73
- indent(concat([softline, path.call(print, "body", 1)])),
74
- concat([softline, "else"]),
75
- indent(concat([softline, path.call(print, "body", 2)])),
76
- concat([softline, "end"])
77
- ]),
78
- concat(
79
- parts.concat(printTernaryConditions(keyword, truthyValue, falsyValue))
80
- )
81
- )
82
- );
116
+ const stmts = path.getValue().body[1];
117
+ const hasComments =
118
+ stmts.type === "stmts" && stmts.body.some(stmt => stmt.type === "@comment");
119
+
120
+ if (!inlineConditionals || hasComments) {
121
+ return multiline;
83
122
  }
84
123
 
85
- // If there is an else and only an else, attempt to shorten to a ternary
86
- if (
124
+ const inline = concat([
125
+ path.call(print, "body", 1),
126
+ ` ${keyword} `,
127
+ path.call(print, "body", 0)
128
+ ]);
129
+
130
+ return group(ifBreak(multiline, inline));
131
+ };
132
+
133
+ // Certain expressions cannot be reduced to a ternary without adding parens
134
+ // around them. In this case we say they cannot be ternaried and default instead
135
+ // to breaking them into multiple lines.
136
+ const canTernaryStmts = stmts =>
137
+ stmts.body.length === 1 && !noTernary.includes(stmts.body[0].type);
138
+
139
+ // In order for an `if` or `unless` expression to be shortened to a ternary,
140
+ // there has to be one and only one "addition" (another clause attached) which
141
+ // is of the "else" type. Both the body of the main node and the body of the
142
+ // additional node must have only one statement, and that statement list must
143
+ // pass the `canTernaryStmts` check.
144
+ const canTernary = path => {
145
+ const [_pred, stmts, addition] = path.getValue().body;
146
+
147
+ return (
87
148
  addition &&
88
149
  addition.type === "else" &&
89
- canTernary(stmts) &&
90
- canTernary(addition.body[0])
91
- ) {
92
- const ternary = printTernaryConditions(
150
+ [stmts, addition.body[0]].every(canTernaryStmts)
151
+ );
152
+ };
153
+
154
+ // A normalized print function for both `if` and `unless` nodes.
155
+ const printConditional = keyword => (path, { inlineConditionals }, print) => {
156
+ if (canTernary(path)) {
157
+ const ternaryConditions = printTernaryClauses(
93
158
  keyword,
94
159
  path.call(print, "body", 1),
95
160
  path.call(print, "body", 2, "body", 0)
@@ -98,36 +163,32 @@ const printConditional = keyword => (path, { inlineConditionals }, print) => {
98
163
  return group(
99
164
  ifBreak(
100
165
  printWithAddition(keyword, path, print),
101
- concat([path.call(print, "body", 0), " ? "].concat(ternary))
166
+ concat([path.call(print, "body", 0), " ? "].concat(ternaryConditions))
102
167
  )
103
168
  );
104
169
  }
105
170
 
106
- // If there's an additional clause, we know we can't go for the inline option
107
- if (addition) {
171
+ // If there's an additional clause that wasn't matched earlier, we know we
172
+ // can't go for the inline option.
173
+ if (path.getValue().body[2]) {
108
174
  return group(printWithAddition(keyword, path, print, { breaking: true }));
109
175
  }
110
176
 
111
- // If it's short enough, favor the inline conditional
112
- return group(
113
- ifBreak(
114
- concat([
115
- `${keyword} `,
116
- align(keyword.length - 1, path.call(print, "body", 0)),
117
- indent(concat([softline, path.call(print, "body", 1)])),
118
- concat([softline, "end"])
119
- ]),
120
- concat([
121
- inlineConditionals ? "" : breakParent,
122
- path.call(print, "body", 1),
123
- ` ${keyword} `,
124
- path.call(print, "body", 0)
125
- ])
126
- )
127
- );
177
+ return printSingle(keyword)(path, { inlineConditionals }, print);
128
178
  };
129
179
 
130
180
  module.exports = {
181
+ else: (path, opts, print) => {
182
+ const stmts = path.getValue().body[0];
183
+
184
+ return concat([
185
+ stmts.body.length === 1 && stmts.body[0].type === "command"
186
+ ? breakParent
187
+ : "",
188
+ "else",
189
+ indent(concat([softline, path.call(print, "body", 0)]))
190
+ ]);
191
+ },
131
192
  elsif: (path, opts, print) => {
132
193
  const [_predicate, _statements, addition] = path.getValue().body;
133
194
  const parts = [
@@ -147,8 +208,8 @@ module.exports = {
147
208
  return group(concat(parts));
148
209
  },
149
210
  if: printConditional("if"),
150
- ifop: printConditional("if"),
151
- if_mod: printConditional("if"),
211
+ ifop: printTernary,
212
+ if_mod: printSingle("if"),
152
213
  unless: printConditional("unless"),
153
- unless_mod: printConditional("unless")
214
+ unless_mod: printSingle("unless")
154
215
  };