prettier 1.1.0 → 1.2.4

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -1
  3. data/CONTRIBUTING.md +2 -2
  4. data/README.md +16 -1
  5. data/lib/prettier.rb +2 -2
  6. data/package.json +2 -2
  7. data/rubocop.yml +26 -0
  8. data/src/{ruby.js → plugin.js} +2 -2
  9. data/src/prettier.js +1 -0
  10. data/src/{embed.js → ruby/embed.js} +6 -2
  11. data/src/{nodes.js → ruby/nodes.js} +0 -0
  12. data/src/{nodes → ruby/nodes}/alias.js +1 -1
  13. data/src/{nodes → ruby/nodes}/aref.js +8 -1
  14. data/src/{nodes → ruby/nodes}/args.js +2 -2
  15. data/src/{nodes → ruby/nodes}/arrays.js +2 -3
  16. data/src/{nodes → ruby/nodes}/assign.js +12 -4
  17. data/src/ruby/nodes/blocks.js +90 -0
  18. data/src/{nodes → ruby/nodes}/calls.js +18 -9
  19. data/src/ruby/nodes/case.js +65 -0
  20. data/src/{nodes → ruby/nodes}/class.js +1 -1
  21. data/src/ruby/nodes/commands.js +126 -0
  22. data/src/{nodes → ruby/nodes}/conditionals.js +3 -3
  23. data/src/{nodes → ruby/nodes}/constants.js +2 -2
  24. data/src/{nodes → ruby/nodes}/flow.js +2 -2
  25. data/src/{nodes → ruby/nodes}/hashes.js +32 -10
  26. data/src/{nodes → ruby/nodes}/heredocs.js +2 -2
  27. data/src/ruby/nodes/hooks.js +34 -0
  28. data/src/{nodes → ruby/nodes}/ints.js +0 -0
  29. data/src/{nodes → ruby/nodes}/lambdas.js +2 -2
  30. data/src/{nodes → ruby/nodes}/loops.js +10 -7
  31. data/src/{nodes → ruby/nodes}/massign.js +8 -1
  32. data/src/{nodes → ruby/nodes}/methods.js +32 -6
  33. data/src/{nodes → ruby/nodes}/operators.js +2 -2
  34. data/src/{nodes → ruby/nodes}/params.js +31 -16
  35. data/src/{nodes → ruby/nodes}/patterns.js +54 -15
  36. data/src/{nodes → ruby/nodes}/regexp.js +2 -2
  37. data/src/{nodes → ruby/nodes}/rescue.js +2 -2
  38. data/src/ruby/nodes/return.js +94 -0
  39. data/src/{nodes → ruby/nodes}/statements.js +6 -9
  40. data/src/{nodes → ruby/nodes}/strings.js +27 -36
  41. data/src/{nodes → ruby/nodes}/super.js +2 -2
  42. data/src/{nodes → ruby/nodes}/undef.js +1 -1
  43. data/src/{parser.js → ruby/parser.js} +4 -3
  44. data/src/{parser.rb → ruby/parser.rb} +498 -492
  45. data/src/{printer.js → ruby/printer.js} +33 -1
  46. data/src/{toProc.js → ruby/toProc.js} +4 -8
  47. data/src/utils.js +10 -93
  48. data/src/utils/containsAssignment.js +11 -0
  49. data/src/utils/getTrailingComma.js +5 -0
  50. data/src/utils/hasAncestor.js +17 -0
  51. data/src/utils/literal.js +7 -0
  52. data/src/utils/makeCall.js +14 -0
  53. data/src/utils/noIndent.js +10 -0
  54. data/src/utils/skipAssignIndent.js +10 -0
  55. metadata +49 -41
  56. data/src/nodes/blocks.js +0 -85
  57. data/src/nodes/case.js +0 -61
  58. data/src/nodes/commands.js +0 -91
  59. data/src/nodes/hooks.js +0 -44
  60. data/src/nodes/return.js +0 -72
@@ -1,5 +1,5 @@
1
- const { concat, group, indent, line, softline } = require("../prettier");
2
- const { noIndent } = require("../utils");
1
+ const { concat, group, indent, line, softline } = require("../../prettier");
2
+ const { noIndent } = require("../../utils");
3
3
 
4
4
  function printBinary(path, opts, print) {
5
5
  const [_leftNode, operator, rightNode] = path.getValue().body;
@@ -1,5 +1,12 @@
1
- const { concat, group, join, indent, line, softline } = require("../prettier");
2
- const { literal } = require("../utils");
1
+ const {
2
+ concat,
3
+ group,
4
+ join,
5
+ indent,
6
+ line,
7
+ softline
8
+ } = require("../../prettier");
9
+ const { literal } = require("../../utils");
3
10
 
4
11
  function printRestParam(symbol) {
5
12
  return function printRestParamWithSymbol(path, opts, print) {
@@ -22,18 +29,22 @@ function printParams(path, opts, print) {
22
29
  let parts = [];
23
30
 
24
31
  if (reqs) {
25
- parts = parts.concat(path.map(print, "body", 0));
32
+ path.each(
33
+ (reqPath) => {
34
+ // For some very strange reason, if you have a comment attached to a
35
+ // rest_param, it shows up here in the list of required params.
36
+ if (reqPath.getValue().type !== "rest_param") {
37
+ parts.push(print(reqPath));
38
+ }
39
+ },
40
+ "body",
41
+ 0
42
+ );
26
43
  }
27
44
 
28
45
  if (optls) {
29
46
  parts = parts.concat(
30
- optls.map((_, index) =>
31
- concat([
32
- path.call(print, "body", 1, index, 0),
33
- " = ",
34
- path.call(print, "body", 1, index, 1)
35
- ])
36
- )
47
+ path.map((optlPath) => join(" = ", optlPath.map(print)), "body", 1)
37
48
  );
38
49
  }
39
50
 
@@ -47,12 +58,16 @@ function printParams(path, opts, print) {
47
58
 
48
59
  if (kwargs) {
49
60
  parts = parts.concat(
50
- kwargs.map(([, value], index) => {
51
- if (!value) {
52
- return path.call(print, "body", 4, index, 0);
53
- }
54
- return group(join(" ", path.map(print, "body", 4, index)));
55
- })
61
+ path.map(
62
+ (kwargPath) => {
63
+ if (!kwargPath.getValue()[1]) {
64
+ return kwargPath.call(print, 0);
65
+ }
66
+ return group(join(" ", kwargPath.map(print)));
67
+ },
68
+ "body",
69
+ 4
70
+ )
56
71
  );
57
72
  }
58
73
 
@@ -1,4 +1,14 @@
1
- const { concat, group, hardline, indent, join, line } = require("../prettier");
1
+ const {
2
+ align,
3
+ concat,
4
+ group,
5
+ hardline,
6
+ indent,
7
+ join,
8
+ line
9
+ } = require("../../prettier");
10
+
11
+ const patterns = ["aryptn", "binary", "fndptn", "hshptn", "rassign"];
2
12
 
3
13
  function printPatternArg(path, opts, print) {
4
14
  // Pinning is a really special syntax in pattern matching that's not really
@@ -34,10 +44,7 @@ function printAryPtn(path, opts, print) {
34
44
 
35
45
  args = group(join(concat([",", line]), args));
36
46
 
37
- if (
38
- constant ||
39
- ["aryptn", "binary", "hshptn"].includes(path.getParentNode().type)
40
- ) {
47
+ if (constant || patterns.includes(path.getParentNode().type)) {
41
48
  args = concat(["[", args, "]"]);
42
49
  }
43
50
 
@@ -48,11 +55,27 @@ function printAryPtn(path, opts, print) {
48
55
  return args;
49
56
  }
50
57
 
58
+ function printFndPtn(path, opts, print) {
59
+ const [constant] = path.getValue().body;
60
+
61
+ let args = [concat(["*", path.call(print, "body", 1)])]
62
+ .concat(path.map(print, "body", 2))
63
+ .concat(concat(["*", path.call(print, "body", 3)]));
64
+
65
+ args = concat(["[", group(join(concat([",", line]), args)), "]"]);
66
+
67
+ if (constant) {
68
+ return concat([path.call(print, "body", 0), args]);
69
+ }
70
+
71
+ return args;
72
+ }
73
+
51
74
  function printHshPtn(path, opts, print) {
52
75
  const [constant, keyValuePairs, keyValueRest] = path.getValue().body;
53
76
  let args = [];
54
77
 
55
- if (keyValuePairs) {
78
+ if (keyValuePairs.length > 0) {
56
79
  const printPair = (pairPath) => {
57
80
  const parts = [pairPath.call(print, 0)];
58
81
 
@@ -80,10 +103,8 @@ function printHshPtn(path, opts, print) {
80
103
 
81
104
  if (constant) {
82
105
  args = concat(["[", args, "]"]);
83
- } else if (
84
- ["aryptn", "binary", "hshptn"].includes(path.getParentNode().type)
85
- ) {
86
- args = concat(["{", args, "}"]);
106
+ } else if (patterns.includes(path.getParentNode().type)) {
107
+ args = concat(["{ ", args, " }"]);
87
108
  }
88
109
 
89
110
  if (constant) {
@@ -96,10 +117,13 @@ function printHshPtn(path, opts, print) {
96
117
  function printIn(path, opts, print) {
97
118
  const parts = [
98
119
  "in ",
99
- path.call(
100
- (valuePath) => printPatternArg(valuePath, opts, print),
101
- "body",
102
- 0
120
+ align(
121
+ "in ".length,
122
+ path.call(
123
+ (valuePath) => printPatternArg(valuePath, opts, print),
124
+ "body",
125
+ 0
126
+ )
103
127
  ),
104
128
  indent(concat([hardline, path.call(print, "body", 1)]))
105
129
  ];
@@ -111,8 +135,23 @@ function printIn(path, opts, print) {
111
135
  return group(concat(parts));
112
136
  }
113
137
 
138
+ function printRAssign(path, opts, print) {
139
+ const { keyword } = path.getValue();
140
+ const [leftDoc, rightDoc] = path.map(print, "body");
141
+
142
+ return group(
143
+ concat([
144
+ leftDoc,
145
+ keyword ? " in" : " =>",
146
+ group(indent(concat([line, rightDoc])))
147
+ ])
148
+ );
149
+ }
150
+
114
151
  module.exports = {
115
152
  aryptn: printAryPtn,
153
+ fndptn: printFndPtn,
116
154
  hshptn: printHshPtn,
117
- in: printIn
155
+ in: printIn,
156
+ rassign: printRAssign
118
157
  };
@@ -1,5 +1,5 @@
1
- const { concat } = require("../prettier");
2
- const { hasAncestor } = require("../utils");
1
+ const { concat } = require("../../prettier");
2
+ const { hasAncestor } = require("../../utils");
3
3
 
4
4
  function hasContent(node, pattern) {
5
5
  return node.body.some(
@@ -6,8 +6,8 @@ const {
6
6
  indent,
7
7
  join,
8
8
  line
9
- } = require("../prettier");
10
- const { literal } = require("../utils");
9
+ } = require("../../prettier");
10
+ const { literal } = require("../../utils");
11
11
 
12
12
  function printBegin(path, opts, print) {
13
13
  return concat([
@@ -0,0 +1,94 @@
1
+ const {
2
+ concat,
3
+ group,
4
+ ifBreak,
5
+ indent,
6
+ line,
7
+ join,
8
+ softline
9
+ } = require("../../prettier");
10
+ const { literal } = require("../../utils");
11
+
12
+ // You can't skip the parentheses if you have comments or certain operators with
13
+ // lower precedence than the return keyword.
14
+ const canSkipParens = (args) => {
15
+ const stmts = args.body[0].body[0];
16
+
17
+ // return(
18
+ // # a
19
+ // b
20
+ // )
21
+ if (stmts.comments) {
22
+ return false;
23
+ }
24
+
25
+ const stmt = stmts.body[0];
26
+
27
+ // return (a or b)
28
+ if (stmt.type === "binary" && ["and", "or"].includes(stmt.body[1])) {
29
+ return false;
30
+ }
31
+
32
+ // return (not a)
33
+ if (stmt.type === "unary" && stmt.oper === "not") {
34
+ return false;
35
+ }
36
+
37
+ return true;
38
+ };
39
+
40
+ const printReturn = (path, opts, print) => {
41
+ let args = path.getValue().body[0].body[0];
42
+ let steps = ["body", 0, "body", 0];
43
+
44
+ if (args.body.length === 1) {
45
+ // If the body of the return contains parens, then just skip directly to the
46
+ // content of the parens so that we can skip printing parens if we don't
47
+ // want them.
48
+ if (args.body[0] && args.body[0].type === "paren" && canSkipParens(args)) {
49
+ args = args.body[0].body[0];
50
+ steps = steps.concat("body", 0, "body", 0);
51
+ }
52
+
53
+ // If we're returning an array literal that isn't a special array, single
54
+ // element array, or an empty array, then we want to grab the arguments so
55
+ // that we can print them out as if they were normal return arguments.
56
+ if (
57
+ args.body[0] &&
58
+ args.body[0].type === "array" &&
59
+ args.body[0].body[0] &&
60
+ args.body[0].body[0].body.length > 1 &&
61
+ ["args", "args_add_star"].includes(args.body[0].body[0].type)
62
+ ) {
63
+ steps = steps.concat("body", 0, "body", 0);
64
+ }
65
+ }
66
+
67
+ // Now that we've established which actual node is the arguments to return,
68
+ // we grab it out of the path by diving down the steps that we've set up.
69
+ const parts = path.call.apply(path, [print].concat(steps));
70
+
71
+ // If we got the value straight out of the parens, then `parts` would only
72
+ // be a singular doc as opposed to an array.
73
+ const value = Array.isArray(parts) ? join(concat([",", line]), parts) : parts;
74
+
75
+ // We only get here if we have comments somewhere that would prevent us from
76
+ // skipping the parentheses.
77
+ if (args.body.length === 1 && args.body[0].type === "paren") {
78
+ return concat(["return", value]);
79
+ }
80
+
81
+ return group(
82
+ concat([
83
+ "return",
84
+ ifBreak(parts.length > 1 ? " [" : "(", " "),
85
+ indent(concat([softline, value])),
86
+ concat([softline, ifBreak(parts.length > 1 ? "]" : ")", "")])
87
+ ])
88
+ );
89
+ };
90
+
91
+ module.exports = {
92
+ return: printReturn,
93
+ return0: literal("return")
94
+ };
@@ -10,7 +10,7 @@ const {
10
10
  literalline,
11
11
  softline,
12
12
  trim
13
- } = require("../prettier");
13
+ } = require("../../prettier");
14
14
 
15
15
  function printBodyStmt(path, opts, print) {
16
16
  const [stmts, rescue, elseClause, ensure] = path.getValue().body;
@@ -30,6 +30,7 @@ function printBodyStmt(path, opts, print) {
30
30
 
31
31
  if (elseClause) {
32
32
  // Before Ruby 2.6, this piece of bodystmt was an explicit "else" node
33
+ /* istanbul ignore next */
33
34
  const stmts =
34
35
  elseClause.type === "else"
35
36
  ? path.call(print, "body", 2, "body", 0)
@@ -69,11 +70,7 @@ function printParen(path, opts, print) {
69
70
  }
70
71
 
71
72
  return group(
72
- concat([
73
- "(",
74
- indent(concat([softline, contentDoc])),
75
- concat([softline, ")"])
76
- ])
73
+ concat(["(", indent(concat([softline, contentDoc])), softline, ")"])
77
74
  );
78
75
  }
79
76
 
@@ -123,12 +120,12 @@ module.exports = {
123
120
  if (lineNo === null) {
124
121
  parts.push(printed);
125
122
  } else if (
126
- stmt.start - lineNo > 1 ||
123
+ stmt.sl - lineNo > 1 ||
127
124
  [stmt.type, stmts[index - 1].type].includes("access_ctrl")
128
125
  ) {
129
126
  parts.push(hardline, hardline, printed);
130
127
  } else if (
131
- stmt.start !== lineNo ||
128
+ stmt.sl !== lineNo ||
132
129
  path.getParentNode().type !== "string_embexpr"
133
130
  ) {
134
131
  parts.push(hardline, printed);
@@ -136,7 +133,7 @@ module.exports = {
136
133
  parts.push("; ", printed);
137
134
  }
138
135
 
139
- lineNo = stmt.end;
136
+ lineNo = stmt.el;
140
137
  });
141
138
 
142
139
  return concat(parts);
@@ -6,7 +6,7 @@ const {
6
6
  literalline,
7
7
  softline,
8
8
  join
9
- } = require("../prettier");
9
+ } = require("../../prettier");
10
10
 
11
11
  // If there is some part of this string that matches an escape sequence or that
12
12
  // contains the interpolation pattern ("#{"), then we are locked into whichever
@@ -31,17 +31,10 @@ function isSingleQuotable(node) {
31
31
 
32
32
  const quotePattern = new RegExp("\\\\([\\s\\S])|(['\"])", "g");
33
33
 
34
- function normalizeQuotes(content, enclosingQuote, originalQuote) {
35
- const replaceOther = originalQuote === '"';
36
- const otherQuote = enclosingQuote === '"' ? "'" : '"';
37
-
34
+ function normalizeQuotes(content, enclosingQuote) {
38
35
  // Escape and unescape single and double quotes as needed to be able to
39
36
  // enclose `content` with `enclosingQuote`.
40
37
  return content.replace(quotePattern, (match, escaped, quote) => {
41
- if (replaceOther && escaped === otherQuote) {
42
- return escaped;
43
- }
44
-
45
38
  if (quote === enclosingQuote) {
46
39
  return `\\${quote}`;
47
40
  }
@@ -97,12 +90,34 @@ function printDynaSymbol(path, opts, print) {
97
90
  return concat([":", quote].concat(path.map(print, "body")).concat(quote));
98
91
  }
99
92
 
93
+ function printStringConcat(path, opts, print) {
94
+ const [leftDoc, rightDoc] = path.map(print, "body");
95
+
96
+ return group(concat([leftDoc, " \\", indent(concat([hardline, rightDoc]))]));
97
+ }
98
+
100
99
  // Prints out an interpolated variable in the string by converting it into an
101
100
  // embedded expression.
102
101
  function printStringDVar(path, opts, print) {
103
102
  return concat(["#{", path.call(print, "body", 0), "}"]);
104
103
  }
105
104
 
105
+ function printStringEmbExpr(path, opts, print) {
106
+ const parts = path.call(print, "body", 0);
107
+
108
+ // If the interpolated expression is inside of a heredoc or an xstring
109
+ // literal (a string that gets sent to the command line) then we don't want
110
+ // to automatically indent, as this can lead to some very odd looking
111
+ // expressions
112
+ if (["heredoc", "xstring_literal"].includes(path.getParentNode().type)) {
113
+ return concat(["#{", parts, "}"]);
114
+ }
115
+
116
+ return group(
117
+ concat(["#{", indent(concat([softline, parts])), concat([softline, "}"])])
118
+ );
119
+ }
120
+
106
121
  // Prints out a literal string. This function does its best to respect the
107
122
  // wishes of the user with regards to single versus double quotes, but if the
108
123
  // string contains any escape expressions then it will just keep the original
@@ -131,10 +146,7 @@ function printStringLiteral(path, { rubySingleQuote }, print) {
131
146
  }
132
147
 
133
148
  // In this case, the part of the string is just regular string content
134
- return join(
135
- literalline,
136
- normalizeQuotes(part.body, quote, node.quote).split("\n")
137
- );
149
+ return join(literalline, normalizeQuotes(part.body, quote).split("\n"));
138
150
  });
139
151
 
140
152
  return concat([quote].concat(parts).concat(getClosingQuote(quote)));
@@ -155,30 +167,9 @@ function printXStringLiteral(path, opts, print) {
155
167
  module.exports = {
156
168
  "@CHAR": printChar,
157
169
  dyna_symbol: printDynaSymbol,
158
- string_concat: (path, opts, print) =>
159
- group(
160
- concat([
161
- path.call(print, "body", 0),
162
- " \\",
163
- indent(concat([hardline, path.call(print, "body", 1)]))
164
- ])
165
- ),
170
+ string_concat: printStringConcat,
166
171
  string_dvar: printStringDVar,
167
- string_embexpr: (path, opts, print) => {
168
- const parts = path.call(print, "body", 0);
169
-
170
- // If the interpolated expression is inside of a heredoc or an xstring
171
- // literal (a string that gets sent to the command line) then we don't want
172
- // to automatically indent, as this can lead to some very odd looking
173
- // expressions
174
- if (["heredoc", "xstring_literal"].includes(path.getParentNode().type)) {
175
- return concat(["#{", parts, "}"]);
176
- }
177
-
178
- return group(
179
- concat(["#{", indent(concat([softline, parts])), concat([softline, "}"])])
180
- );
181
- },
172
+ string_embexpr: printStringEmbExpr,
182
173
  string_literal: printStringLiteral,
183
174
  symbol_literal: printSymbolLiteral,
184
175
  xstring_literal: printXStringLiteral