prettier 0.12.2

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.
@@ -0,0 +1,32 @@
1
+ const { concat, join } = require("../builders");
2
+
3
+ const usingSymbols = path => {
4
+ const [left, right] = path.getValue().body.map(node => node.body[0].type);
5
+ return left === "symbol" && right === "symbol";
6
+ };
7
+
8
+ const identFromSymbol = (path, print, index) =>
9
+ path.call(print, "body", index, "body", 0, "body", 0);
10
+
11
+ const aliasError = (_path, _opts, _print) => {
12
+ throw new Error("can't make alias for the number variables");
13
+ };
14
+
15
+ const aliasVars = (path, opts, print) => {
16
+ if (usingSymbols(path)) {
17
+ return join(" ", [
18
+ identFromSymbol(path, print, 0),
19
+ identFromSymbol(path, print, 1)
20
+ ]);
21
+ }
22
+ return join(" ", path.map(print, "body"));
23
+ };
24
+
25
+ const alias = (path, opts, print) =>
26
+ concat(["alias ", aliasVars(path, opts, print)]);
27
+
28
+ module.exports = {
29
+ alias,
30
+ alias_error: aliasError,
31
+ var_alias: alias
32
+ };
@@ -0,0 +1,162 @@
1
+ const {
2
+ concat,
3
+ group,
4
+ ifBreak,
5
+ indent,
6
+ join,
7
+ line,
8
+ literalline,
9
+ softline
10
+ } = require("../builders");
11
+
12
+ const isStringArray = args =>
13
+ args.body.every(
14
+ arg =>
15
+ arg.type === "string_literal" &&
16
+ arg.body[0].body.length === 1 &&
17
+ arg.body[0].body[0].type === "@tstring_content" &&
18
+ !arg.body[0].body[0].body.includes(" ")
19
+ );
20
+
21
+ const isSymbolArray = args =>
22
+ args.body.every(arg => arg.type === "symbol_literal");
23
+
24
+ const makeArray = start => (path, opts, print) =>
25
+ [start].concat(path.map(print, "body"));
26
+
27
+ const getSpecialArrayParts = (path, print, args) =>
28
+ args.body.map((_arg, index) =>
29
+ path.call(print, "body", 0, "body", index, "body", 0, "body", 0)
30
+ );
31
+
32
+ const printAref = (path, opts, print) =>
33
+ group(
34
+ concat([
35
+ path.call(print, "body", 0),
36
+ "[",
37
+ indent(
38
+ concat([
39
+ softline,
40
+ join(concat([",", line]), path.call(print, "body", 1))
41
+ ])
42
+ ),
43
+ concat([softline, "]"])
44
+ ])
45
+ );
46
+
47
+ const printSpecialArray = parts =>
48
+ group(
49
+ concat([
50
+ parts[0],
51
+ "[",
52
+ indent(concat([softline, join(line, parts.slice(1))])),
53
+ concat([softline, "]"])
54
+ ])
55
+ );
56
+
57
+ // Extract out the actual elements, taking into account nesting with
58
+ // `args_add_star` nodes. The only nodes that get passed into this function are
59
+ // `args` or `args_add_star`.
60
+ const getElements = (node, elementPath) => {
61
+ if (node.type === "args") {
62
+ return node.body.map((element, index) => ({
63
+ element,
64
+ elementPath: elementPath.concat(["body", index])
65
+ }));
66
+ }
67
+
68
+ return getElements(node.body[0], elementPath.concat(["body", 0])).concat(
69
+ node.body.slice(1).map((element, index) => ({
70
+ element,
71
+ elementPath: elementPath.concat(["body", index + 1])
72
+ }))
73
+ );
74
+ };
75
+
76
+ module.exports = {
77
+ aref: (path, opts, print) => {
78
+ if (!path.getValue().body[1]) {
79
+ return concat([path.call(print, "body", 0), "[]"]);
80
+ }
81
+
82
+ return printAref(path, opts, print);
83
+ },
84
+ aref_field: printAref,
85
+ array: (path, { addTrailingCommas }, print) => {
86
+ const args = path.getValue().body[0];
87
+
88
+ if (args === null) {
89
+ return "[]";
90
+ }
91
+
92
+ if (isStringArray(args)) {
93
+ return printSpecialArray(
94
+ ["%w"].concat(getSpecialArrayParts(path, print, args))
95
+ );
96
+ }
97
+
98
+ if (isSymbolArray(args)) {
99
+ return printSpecialArray(
100
+ ["%i"].concat(getSpecialArrayParts(path, print, args))
101
+ );
102
+ }
103
+
104
+ if (!["args", "args_add_star"].includes(args.type)) {
105
+ return printSpecialArray(path.call(print, "body", 0));
106
+ }
107
+
108
+ const normalDocs = [];
109
+
110
+ const elementDocs = path.call(print, "body", 0);
111
+ const elements = getElements(path.getValue().body[0], ["body", 0]);
112
+
113
+ // We need to manually loop through the elements in the array in order to
114
+ // take care of heredocs printing (their commas go after the opening, as
115
+ // opposed to at the end).
116
+ elements.forEach(({ element, elementPath }, index) => {
117
+ const isInner = index !== elements.length - 1;
118
+
119
+ const isStraightHeredoc = element.type === "heredoc";
120
+ const isSquigglyHeredoc =
121
+ element.type === "string_literal" && element.body[0].type === "heredoc";
122
+
123
+ if (isStraightHeredoc || isSquigglyHeredoc) {
124
+ const heredocNode = isStraightHeredoc ? element : element.body[0];
125
+ const heredocPath = [print].concat(elementPath);
126
+
127
+ if (isSquigglyHeredoc) {
128
+ heredocPath.push("body", 0);
129
+ }
130
+
131
+ normalDocs.push(
132
+ heredocNode.beging,
133
+ isInner || addTrailingCommas ? "," : "",
134
+ literalline,
135
+ concat(path.map.apply(path, heredocPath.concat("body"))),
136
+ heredocNode.ending,
137
+ isInner ? line : ""
138
+ );
139
+ } else {
140
+ normalDocs.push(elementDocs[index]);
141
+
142
+ if (isInner) {
143
+ normalDocs.push(concat([",", line]));
144
+ } else if (addTrailingCommas) {
145
+ normalDocs.push(ifBreak(",", ""));
146
+ }
147
+ }
148
+ });
149
+
150
+ return group(
151
+ concat([
152
+ "[",
153
+ indent(concat([softline].concat(normalDocs))),
154
+ concat([softline, "]"])
155
+ ])
156
+ );
157
+ },
158
+ qsymbols: makeArray("%i"),
159
+ qwords: makeArray("%w"),
160
+ symbols: makeArray("%I"),
161
+ words: makeArray("%W")
162
+ };
@@ -0,0 +1,66 @@
1
+ const {
2
+ breakParent,
3
+ concat,
4
+ group,
5
+ ifBreak,
6
+ indent,
7
+ softline
8
+ } = require("../builders");
9
+ const { hasAncestor } = require("../utils");
10
+
11
+ const printBlock = (path, opts, print) => {
12
+ const [variables, statements] = path.getValue().body;
13
+ const stmts =
14
+ statements.type === "stmts" ? statements.body : statements.body[0].body;
15
+
16
+ let doBlockBody = "";
17
+ if (stmts.length !== 1 || stmts[0].type !== "void_stmt") {
18
+ doBlockBody = indent(concat([softline, path.call(print, "body", 1)]));
19
+ }
20
+
21
+ // If this block is nested underneath a command or command_call node, then we
22
+ // can't use `do...end` because that will get associated with the parent node
23
+ // as opposed to the current node (because of the difference in operator
24
+ // precedence). Instead, we still use a multi-line format but switch to using
25
+ // braces instead.
26
+ const useBraces = hasAncestor(path, ["command", "command_call"]);
27
+
28
+ const doBlock = concat([
29
+ useBraces ? " {" : " do",
30
+ variables ? concat([" ", path.call(print, "body", 0)]) : "",
31
+ doBlockBody,
32
+ concat([softline, useBraces ? "}" : "end"])
33
+ ]);
34
+
35
+ // We can hit this next pattern if within the block the only statement is a
36
+ // comment.
37
+ if (
38
+ stmts.length > 1 &&
39
+ stmts.filter(stmt => stmt.type !== "@comment").length === 1
40
+ ) {
41
+ return concat([breakParent, doBlock]);
42
+ }
43
+
44
+ // If the parent node is a command node, then there are no parentheses around
45
+ // the arguments to that command, so we need to break the block
46
+ if (["command", "command_call"].includes(path.getParentNode().body[0].type)) {
47
+ return concat([breakParent, doBlock]);
48
+ }
49
+
50
+ const hasBody = stmts.some(({ type }) => type !== "void_stmt");
51
+ const braceBlock = concat([
52
+ " {",
53
+ hasBody || variables ? " " : "",
54
+ variables ? path.call(print, "body", 0) : "",
55
+ path.call(print, "body", 1),
56
+ hasBody ? " " : "",
57
+ "}"
58
+ ]);
59
+
60
+ return group(ifBreak(doBlock, braceBlock));
61
+ };
62
+
63
+ module.exports = {
64
+ brace_block: printBlock,
65
+ do_block: printBlock
66
+ };
@@ -0,0 +1,28 @@
1
+ const { concat, group, indent, softline } = require("../builders");
2
+ const { makeCall } = require("../utils");
3
+
4
+ const noIndent = ["array", "hash", "method_add_block", "xstring_literal"];
5
+
6
+ module.exports = {
7
+ call: (path, opts, print) => {
8
+ const receiver = path.call(print, "body", 0);
9
+ const operator = makeCall(path, opts, print);
10
+ let name = path.getValue().body[2];
11
+
12
+ // You can call lambdas with a special syntax that looks like func.(*args).
13
+ // In this case, "call" is returned for the 3rd child node.
14
+ if (name !== "call") {
15
+ name = path.call(print, "body", 2);
16
+ }
17
+
18
+ // For certain left sides of the call nodes, we want to attach directly to
19
+ // the } or end.
20
+ if (noIndent.includes(path.getValue().body[0].type)) {
21
+ return concat([receiver, operator, name]);
22
+ }
23
+
24
+ return group(
25
+ concat([receiver, indent(concat([softline, operator, name]))])
26
+ );
27
+ }
28
+ };
@@ -0,0 +1,57 @@
1
+ const {
2
+ align,
3
+ concat,
4
+ fill,
5
+ group,
6
+ hardline,
7
+ indent,
8
+ line
9
+ } = require("../builders");
10
+
11
+ module.exports = {
12
+ case: (path, opts, print) => {
13
+ const statement = ["case"];
14
+
15
+ // You don't need to explicitly have something to test against in a case
16
+ // statement (without it it effectively becomes an if/elsif chain).
17
+ if (path.getValue().body[0]) {
18
+ statement.push(" ", path.call(print, "body", 0));
19
+ }
20
+
21
+ return concat(
22
+ statement.concat([hardline, path.call(print, "body", 1), hardline, "end"])
23
+ );
24
+ },
25
+ when: (path, opts, print) => {
26
+ const [_preds, _stmts, addition] = path.getValue().body;
27
+
28
+ // The `fill` builder command expects an array of docs alternating with
29
+ // line breaks. This is so it can loop through and determine where to break.
30
+ const preds = fill(
31
+ path
32
+ .call(print, "body", 0)
33
+ .reduce(
34
+ (accum, pred, index) =>
35
+ index === 0 ? [pred] : accum.concat([",", line, pred]),
36
+ null
37
+ )
38
+ );
39
+
40
+ const stmts = path.call(print, "body", 1);
41
+ const parts = [concat(["when ", align("when ".length, preds)])];
42
+
43
+ // It's possible in a when to just have empty void statements, in which case
44
+ // we would skip adding the body.
45
+ if (!stmts.parts.every(part => !part)) {
46
+ parts.push(indent(concat([hardline, stmts])));
47
+ }
48
+
49
+ // This is the next clause on the case statement, either another `when` or
50
+ // an `else` clause.
51
+ if (addition) {
52
+ parts.push(hardline, path.call(print, "body", 2));
53
+ }
54
+
55
+ return group(concat(parts));
56
+ }
57
+ };
@@ -0,0 +1,70 @@
1
+ const { align, concat, group, ifBreak, join, line } = require("../builders");
2
+ const { docLength, makeArgs, makeCall } = require("../utils");
3
+
4
+ const hasDef = node =>
5
+ node.body[1].type === "args_add_block" &&
6
+ node.body[1].body[0].type === "args" &&
7
+ node.body[1].body[0].body[0].type === "def";
8
+
9
+ module.exports = {
10
+ command: (path, opts, print) => {
11
+ const command = path.call(print, "body", 0);
12
+ const { args, heredocs } = makeArgs(path, opts, print, 1);
13
+
14
+ if (heredocs.length > 1) {
15
+ return concat([command, " ", join(", ", args)].concat(heredocs));
16
+ }
17
+
18
+ const joinedArgs = join(concat([",", line]), args);
19
+ const breakArgs = hasDef(path.getValue())
20
+ ? joinedArgs
21
+ : align(command.length + 1, joinedArgs);
22
+
23
+ const commandDoc = group(
24
+ ifBreak(
25
+ concat([command, " ", breakArgs]),
26
+ concat([command, " ", joinedArgs])
27
+ )
28
+ );
29
+
30
+ if (heredocs.length === 1) {
31
+ return group(concat([commandDoc].concat(heredocs)));
32
+ }
33
+
34
+ return commandDoc;
35
+ },
36
+ command_call: (path, opts, print) => {
37
+ const parts = [
38
+ path.call(print, "body", 0),
39
+ makeCall(path, opts, print),
40
+ path.call(print, "body", 2)
41
+ ];
42
+
43
+ if (!path.getValue().body[3]) {
44
+ return concat(parts);
45
+ }
46
+
47
+ parts.push(" ");
48
+ const { args, heredocs } = makeArgs(path, opts, print, 3);
49
+
50
+ if (heredocs.length > 1) {
51
+ return concat(parts.concat([join(", ", args)]).concat(heredocs));
52
+ }
53
+
54
+ const joinedArgs = join(concat([",", line]), args);
55
+ const breakArgs =
56
+ path.getValue().body[2].body === "to"
57
+ ? joinedArgs
58
+ : align(docLength(concat(parts)), joinedArgs);
59
+
60
+ const commandDoc = group(
61
+ ifBreak(concat(parts.concat(breakArgs)), concat(parts.concat(joinedArgs)))
62
+ );
63
+
64
+ if (heredocs.length === 1) {
65
+ return group(concat([commandDoc].concat(heredocs)));
66
+ }
67
+
68
+ return commandDoc;
69
+ }
70
+ };
@@ -0,0 +1,154 @@
1
+ const {
2
+ align,
3
+ breakParent,
4
+ concat,
5
+ hardline,
6
+ group,
7
+ ifBreak,
8
+ indent,
9
+ softline
10
+ } = require("../builders");
11
+
12
+ const noTernary = [
13
+ "@comment",
14
+ "alias",
15
+ "assign",
16
+ "break",
17
+ "command",
18
+ "command_call",
19
+ "if_mod",
20
+ "ifop",
21
+ "lambda",
22
+ "massign",
23
+ "next",
24
+ "opassign",
25
+ "rescue_mod",
26
+ "return",
27
+ "return0",
28
+ "super",
29
+ "undef",
30
+ "unless_mod",
31
+ "until_mod",
32
+ "var_alias",
33
+ "void_stmt",
34
+ "while_mod",
35
+ "yield",
36
+ "yield0",
37
+ "zsuper"
38
+ ];
39
+
40
+ const printWithAddition = (keyword, path, print, { breaking = false } = {}) =>
41
+ concat([
42
+ `${keyword} `,
43
+ align(keyword.length - 1, path.call(print, "body", 0)),
44
+ indent(concat([softline, path.call(print, "body", 1)])),
45
+ concat([softline, path.call(print, "body", 2)]),
46
+ concat([softline, "end"]),
47
+ breaking ? breakParent : ""
48
+ ]);
49
+
50
+ const printTernaryConditions = (keyword, truthyValue, falsyValue) => {
51
+ const parts = [truthyValue, " : ", falsyValue];
52
+ return keyword === "if" ? parts : parts.reverse();
53
+ };
54
+
55
+ const canTernary = stmts =>
56
+ stmts.body.length === 1 && !noTernary.includes(stmts.body[0].type);
57
+
58
+ const printConditional = keyword => (path, { inlineConditionals }, print) => {
59
+ const [_predicate, stmts, addition] = path.getValue().body;
60
+
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);
67
+
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
+ );
83
+ }
84
+
85
+ // If there is an else and only an else, attempt to shorten to a ternary
86
+ if (
87
+ addition &&
88
+ addition.type === "else" &&
89
+ canTernary(stmts) &&
90
+ canTernary(addition.body[0])
91
+ ) {
92
+ const ternary = printTernaryConditions(
93
+ keyword,
94
+ path.call(print, "body", 1),
95
+ path.call(print, "body", 2, "body", 0)
96
+ );
97
+
98
+ return group(
99
+ ifBreak(
100
+ printWithAddition(keyword, path, print),
101
+ concat([path.call(print, "body", 0), " ? "].concat(ternary))
102
+ )
103
+ );
104
+ }
105
+
106
+ // If there's an additional clause, we know we can't go for the inline option
107
+ if (addition) {
108
+ return group(printWithAddition(keyword, path, print, { breaking: true }));
109
+ }
110
+
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
+ );
128
+ };
129
+
130
+ module.exports = {
131
+ elsif: (path, opts, print) => {
132
+ const [_predicate, _statements, addition] = path.getValue().body;
133
+ const parts = [
134
+ group(
135
+ concat([
136
+ "elsif ",
137
+ align("elsif".length - 1, path.call(print, "body", 0))
138
+ ])
139
+ ),
140
+ indent(concat([hardline, path.call(print, "body", 1)]))
141
+ ];
142
+
143
+ if (addition) {
144
+ parts.push(group(concat([hardline, path.call(print, "body", 2)])));
145
+ }
146
+
147
+ return group(concat(parts));
148
+ },
149
+ if: printConditional("if"),
150
+ ifop: printConditional("if"),
151
+ if_mod: printConditional("if"),
152
+ unless: printConditional("unless"),
153
+ unless_mod: printConditional("unless")
154
+ };