prettier 1.0.0.pre.rc2 → 1.2.1

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.
@@ -8,54 +8,58 @@ const {
8
8
  line
9
9
  } = require("../prettier");
10
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.call(print, "body", 0).reduce((accum, pred, index) => {
32
- if (index === 0) {
33
- return [pred];
34
- }
35
-
36
- // Pull off the last element and make it concat with a comma so that
37
- // we can maintain alternating lines and docs.
38
- return accum
39
- .slice(0, -1)
40
- .concat([concat([accum[accum.length - 1], ","]), line, pred]);
41
- }, null)
42
- );
43
-
44
- const stmts = path.call(print, "body", 1);
45
- const parts = [concat(["when ", align("when ".length, preds)])];
46
-
47
- // It's possible in a when to just have empty void statements, in which case
48
- // we would skip adding the body.
49
- if (!stmts.parts.every((part) => !part)) {
50
- parts.push(indent(concat([hardline, stmts])));
51
- }
52
-
53
- // This is the next clause on the case statement, either another `when` or
54
- // an `else` clause.
55
- if (addition) {
56
- parts.push(hardline, path.call(print, "body", 2));
57
- }
58
-
59
- return group(concat(parts));
11
+ function printCase(path, opts, print) {
12
+ const statement = ["case"];
13
+
14
+ // You don't need to explicitly have something to test against in a case
15
+ // statement (without it it effectively becomes an if/elsif chain).
16
+ if (path.getValue().body[0]) {
17
+ statement.push(" ", path.call(print, "body", 0));
18
+ }
19
+
20
+ return concat(
21
+ statement.concat([hardline, path.call(print, "body", 1), hardline, "end"])
22
+ );
23
+ }
24
+
25
+ function printWhen(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.call(print, "body", 0).reduce((accum, pred, index) => {
32
+ if (index === 0) {
33
+ return [pred];
34
+ }
35
+
36
+ // Pull off the last element and make it concat with a comma so that
37
+ // we can maintain alternating lines and docs.
38
+ return accum
39
+ .slice(0, -1)
40
+ .concat([concat([accum[accum.length - 1], ","]), line, pred]);
41
+ }, null)
42
+ );
43
+
44
+ const stmts = path.call(print, "body", 1);
45
+ const parts = [concat(["when ", align("when ".length, preds)])];
46
+
47
+ // It's possible in a when to just have empty void statements, in which case
48
+ // we would skip adding the body.
49
+ if (!stmts.parts.every((part) => !part)) {
50
+ parts.push(indent(concat([hardline, stmts])));
51
+ }
52
+
53
+ // This is the next clause on the case statement, either another `when` or
54
+ // an `else` clause.
55
+ if (addition) {
56
+ parts.push(hardline, path.call(print, "body", 2));
60
57
  }
58
+
59
+ return group(concat(parts));
60
+ }
61
+
62
+ module.exports = {
63
+ case: printCase,
64
+ when: printWhen
61
65
  };
@@ -1,14 +1,11 @@
1
- const {
2
- concat,
3
- group,
4
- hardline,
5
- ifBreak,
6
- indent,
7
- join,
8
- line
9
- } = require("../prettier");
1
+ const { concat, group, ifBreak, indent, join, line } = require("../prettier");
10
2
 
11
- const { getTrailingComma, prefix, skipAssignIndent } = require("../utils");
3
+ const {
4
+ getTrailingComma,
5
+ prefix,
6
+ printEmptyCollection,
7
+ skipAssignIndent
8
+ } = require("../utils");
12
9
 
13
10
  // When attempting to convert a hash rocket into a hash label, you need to take
14
11
  // care because only certain patterns are allowed. Ruby source says that they
@@ -93,50 +90,7 @@ function printHashContents(path, opts, print) {
93
90
  ? printHashKeyLabel
94
91
  : printHashKeyRocket;
95
92
 
96
- const contents = join(concat([",", line]), path.map(print, "body"));
97
-
98
- // If we're inside a hash literal, then we want to add the braces at this
99
- // level so that the grouping is correct. Otherwise you could end up with
100
- // opening and closing braces being split up, but the contents not being split
101
- // correctly.
102
- if (path.getParentNode().type === "hash") {
103
- return group(
104
- concat([
105
- "{",
106
- indent(
107
- concat([
108
- line,
109
- contents,
110
- getTrailingComma(opts) ? ifBreak(",", "") : ""
111
- ])
112
- ),
113
- line,
114
- "}"
115
- ])
116
- );
117
- }
118
-
119
- // Otherwise, we're inside a bare_assoc_hash, so we don't want to print
120
- // braces at all.
121
- return group(contents);
122
- }
123
-
124
- function printEmptyHashWithComments(path, opts) {
125
- const hashNode = path.getValue();
126
-
127
- const printComment = (commentPath, index) => {
128
- hashNode.comments[index].printed = true;
129
- return opts.printer.printComment(commentPath);
130
- };
131
-
132
- return concat([
133
- "{",
134
- indent(
135
- concat([hardline, join(hardline, path.map(printComment, "comments"))])
136
- ),
137
- line,
138
- "}"
139
- ]);
93
+ return join(concat([",", line]), path.map(print, "body"));
140
94
  }
141
95
 
142
96
  function printHash(path, opts, print) {
@@ -146,10 +100,23 @@ function printHash(path, opts, print) {
146
100
  // missing, then it means we're dealing with an empty hash, so we can just
147
101
  // exit here and print.
148
102
  if (hashNode.body[0] === null) {
149
- return hashNode.comments ? printEmptyHashWithComments(path, opts) : "{}";
103
+ return printEmptyCollection(path, opts, "{", "}");
150
104
  }
151
105
 
152
- return path.call(print, "body", 0);
106
+ return group(
107
+ concat([
108
+ "{",
109
+ indent(
110
+ concat([
111
+ line,
112
+ path.call(print, "body", 0),
113
+ getTrailingComma(opts) ? ifBreak(",", "") : ""
114
+ ])
115
+ ),
116
+ line,
117
+ "}"
118
+ ])
119
+ );
153
120
  }
154
121
 
155
122
  module.exports = {
@@ -12,85 +12,85 @@ const {
12
12
  const { containsAssignment } = require("../utils");
13
13
  const inlineEnsureParens = require("../utils/inlineEnsureParens");
14
14
 
15
- const printLoop = (keyword, modifier) => (path, { rubyModifier }, print) => {
16
- const [_predicate, stmts] = path.getValue().body;
15
+ function printLoop(keyword, modifier) {
16
+ return function printLoopWithOptions(path, { rubyModifier }, print) {
17
+ const [_predicate, stmts] = path.getValue().body;
17
18
 
18
- // If the only statement inside this while loop is a void statement, then we
19
- // can shorten to just displaying the predicate and then a semicolon.
20
- if (
21
- stmts.body.length === 1 &&
22
- stmts.body[0].type === "void_stmt" &&
23
- !stmts.body[0].comments
24
- ) {
25
- return group(
26
- concat([
27
- keyword,
28
- " ",
29
- path.call(print, "body", 0),
30
- ifBreak(softline, "; "),
31
- "end"
19
+ // If the only statement inside this while loop is a void statement, then we
20
+ // can shorten to just displaying the predicate and then a semicolon.
21
+ if (
22
+ stmts.body.length === 1 &&
23
+ stmts.body[0].type === "void_stmt" &&
24
+ !stmts.body[0].comments
25
+ ) {
26
+ return group(
27
+ concat([
28
+ keyword,
29
+ " ",
30
+ path.call(print, "body", 0),
31
+ ifBreak(softline, "; "),
32
+ "end"
33
+ ])
34
+ );
35
+ }
36
+
37
+ const inlineLoop = concat(
38
+ inlineEnsureParens(path, [
39
+ path.call(print, "body", 1),
40
+ ` ${keyword} `,
41
+ path.call(print, "body", 0)
32
42
  ])
33
43
  );
34
- }
35
44
 
36
- const inlineLoop = concat(
37
- inlineEnsureParens(path, [
38
- path.call(print, "body", 1),
39
- ` ${keyword} `,
40
- path.call(print, "body", 0)
41
- ])
42
- );
45
+ // If we're in the modifier form and we're modifying a `begin`, then this is
46
+ // a special case where we need to explicitly use the modifier form because
47
+ // otherwise the semantic meaning changes. This looks like:
48
+ //
49
+ // begin
50
+ // foo
51
+ // end while bar
52
+ //
53
+ // The above is effectively a `do...while` loop (which we don't have in
54
+ // ruby).
55
+ if (modifier && path.getValue().body[1].type === "begin") {
56
+ return inlineLoop;
57
+ }
43
58
 
44
- // If we're in the modifier form and we're modifying a `begin`, then this is a
45
- // special case where we need to explicitly use the modifier form because
46
- // otherwise the semantic meaning changes. This looks like:
47
- //
48
- // begin
49
- // foo
50
- // end while bar
51
- //
52
- // The above is effectively a `do...while` loop (which we don't have in ruby).
53
- if (modifier && path.getValue().body[1].type === "begin") {
54
- return inlineLoop;
55
- }
59
+ const blockLoop = concat([
60
+ concat([
61
+ `${keyword} `,
62
+ align(keyword.length + 1, path.call(print, "body", 0))
63
+ ]),
64
+ indent(concat([softline, path.call(print, "body", 1)])),
65
+ concat([softline, "end"])
66
+ ]);
56
67
 
57
- const blockLoop = concat([
58
- concat([
59
- `${keyword} `,
60
- align(keyword.length + 1, path.call(print, "body", 0))
61
- ]),
62
- indent(concat([softline, path.call(print, "body", 1)])),
63
- concat([softline, "end"])
64
- ]);
68
+ // If we're disallowing inline loops or if the predicate of the loop
69
+ // contains an assignment (in which case we can't know for certain that that
70
+ // assignment doesn't impact the statements inside the loop) then we can't
71
+ // use the modifier form and we must use the block form.
72
+ if (!rubyModifier || containsAssignment(path.getValue().body[0])) {
73
+ return concat([breakParent, blockLoop]);
74
+ }
65
75
 
66
- // If we're disallowing inline loops or if the predicate of the loop contains
67
- // an assignment (in which case we can't know for certain that that
68
- // assignment doesn't impact the statements inside the loop) then we can't
69
- // use the modifier form and we must use the block form.
70
- if (!rubyModifier || containsAssignment(path.getValue().body[0])) {
71
- return concat([breakParent, blockLoop]);
72
- }
76
+ return group(ifBreak(blockLoop, inlineLoop));
77
+ };
78
+ }
73
79
 
74
- return group(ifBreak(blockLoop, inlineLoop));
75
- };
80
+ function printFor(path, opts, print) {
81
+ const [variable, range, stmts] = path.map(print, "body");
76
82
 
77
- // Technically this is incorrect. A `for` loop actually introduces and modifies
78
- // a local variable that then remains in the outer scope. Additionally, if the
79
- // `each` method was somehow missing from the enumerable (it's possible...),
80
- // then this transformation would fail. However - I've never actually seen a
81
- // `for` loop used in production. If someone actually calls me on it, I'll fix
82
- // this, but for now I'm leaving it.
83
- const printFor = (path, opts, print) =>
84
- group(
83
+ return group(
85
84
  concat([
86
- path.call(print, "body", 1),
87
- ".each do |",
88
- path.call(print, "body", 0),
89
- "|",
90
- indent(concat([hardline, path.call(print, "body", 2)])),
85
+ "for ",
86
+ variable,
87
+ " in ",
88
+ range,
89
+ indent(concat([hardline, stmts])),
91
90
  concat([hardline, "end"])
92
91
  ])
93
92
  );
93
+ }
94
94
 
95
95
  module.exports = {
96
96
  while: printLoop("while", false),
@@ -1,4 +1,4 @@
1
- const { concat, group, hardline, indent } = require("../prettier");
1
+ const { concat, group, hardline, indent, line } = require("../prettier");
2
2
  const { first } = require("../utils");
3
3
 
4
4
  function printMethod(offset) {
@@ -16,8 +16,7 @@ function printMethod(offset) {
16
16
  }
17
17
 
18
18
  // In case there are no parens but there are arguments
19
- const parens =
20
- params.type === "params" && params.body.some((paramType) => paramType);
19
+ const parens = params.type === "params" && params.body.some((type) => type);
21
20
 
22
21
  declaration.push(
23
22
  path.call(print, "body", offset),
@@ -48,8 +47,34 @@ function printMethod(offset) {
48
47
  };
49
48
  }
50
49
 
50
+ function printSingleLineMethod(path, opts, print) {
51
+ let paramsNode = path.getValue().body[1];
52
+ let paramsDoc = "";
53
+
54
+ if (paramsNode) {
55
+ if (paramsNode.body[0].type === "params") {
56
+ paramsNode = paramsNode.body[0];
57
+ }
58
+
59
+ if (paramsNode.type === "params" && paramsNode.body.some((type) => type)) {
60
+ paramsDoc = path.call(print, "body", 1);
61
+ }
62
+ }
63
+
64
+ return group(
65
+ concat([
66
+ "def ",
67
+ path.call(print, "body", 0),
68
+ paramsDoc,
69
+ " =",
70
+ indent(group(concat([line, path.call(print, "body", 2)])))
71
+ ])
72
+ );
73
+ }
74
+
51
75
  module.exports = {
52
76
  access_ctrl: first,
53
77
  def: printMethod(0),
54
- defs: printMethod(2)
78
+ defs: printMethod(2),
79
+ defsl: printSingleLineMethod
55
80
  };
@@ -1,5 +1,7 @@
1
1
  const { concat, group, hardline, indent, join, line } = require("../prettier");
2
2
 
3
+ const patterns = ["aryptn", "binary", "fndptn", "hshptn", "rassign"];
4
+
3
5
  function printPatternArg(path, opts, print) {
4
6
  // Pinning is a really special syntax in pattern matching that's not really
5
7
  // all that well supported in ripper. Here we're just going to the original
@@ -34,10 +36,7 @@ function printAryPtn(path, opts, print) {
34
36
 
35
37
  args = group(join(concat([",", line]), args));
36
38
 
37
- if (
38
- constant ||
39
- ["aryptn", "binary", "hshptn"].includes(path.getParentNode().type)
40
- ) {
39
+ if (constant || patterns.includes(path.getParentNode().type)) {
41
40
  args = concat(["[", args, "]"]);
42
41
  }
43
42
 
@@ -48,6 +47,22 @@ function printAryPtn(path, opts, print) {
48
47
  return args;
49
48
  }
50
49
 
50
+ function printFndPtn(path, opts, print) {
51
+ const [constant] = path.getValue().body;
52
+
53
+ let args = [concat(["*", path.call(print, "body", 1)])]
54
+ .concat(path.map(print, "body", 2))
55
+ .concat(concat(["*", path.call(print, "body", 3)]));
56
+
57
+ args = concat(["[", group(join(concat([",", line]), args)), "]"]);
58
+
59
+ if (constant) {
60
+ return concat([path.call(print, "body", 0), args]);
61
+ }
62
+
63
+ return args;
64
+ }
65
+
51
66
  function printHshPtn(path, opts, print) {
52
67
  const [constant, keyValuePairs, keyValueRest] = path.getValue().body;
53
68
  let args = [];
@@ -80,10 +95,8 @@ function printHshPtn(path, opts, print) {
80
95
 
81
96
  if (constant) {
82
97
  args = concat(["[", args, "]"]);
83
- } else if (
84
- ["aryptn", "binary", "hshptn"].includes(path.getParentNode().type)
85
- ) {
86
- args = concat(["{", args, "}"]);
98
+ } else if (patterns.includes(path.getParentNode().type)) {
99
+ args = concat(["{ ", args, " }"]);
87
100
  }
88
101
 
89
102
  if (constant) {
@@ -111,8 +124,23 @@ function printIn(path, opts, print) {
111
124
  return group(concat(parts));
112
125
  }
113
126
 
127
+ function printRAssign(path, opts, print) {
128
+ const { keyword } = path.getValue();
129
+ const [leftDoc, rightDoc] = path.map(print, "body");
130
+
131
+ return group(
132
+ concat([
133
+ leftDoc,
134
+ keyword ? " in" : " =>",
135
+ group(indent(concat([line, rightDoc])))
136
+ ])
137
+ );
138
+ }
139
+
114
140
  module.exports = {
115
141
  aryptn: printAryPtn,
142
+ fndptn: printFndPtn,
116
143
  hshptn: printHshPtn,
117
- in: printIn
144
+ in: printIn,
145
+ rassign: printRAssign
118
146
  };