prettier 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -1
  3. data/dist/haml/parser.rb +6 -0
  4. data/dist/parser/getInfo.js +9 -2
  5. data/dist/parser/server.rb +6 -2
  6. data/dist/rbs/parser.rb +59 -2
  7. data/dist/rbs/printer.js +14 -6
  8. data/dist/ruby/embed.js +10 -5
  9. data/dist/ruby/location.js +19 -0
  10. data/dist/ruby/nodes/alias.js +6 -5
  11. data/dist/ruby/nodes/aref.js +4 -6
  12. data/dist/ruby/nodes/args.js +29 -56
  13. data/dist/ruby/nodes/arrays.js +31 -35
  14. data/dist/ruby/nodes/assign.js +19 -23
  15. data/dist/ruby/nodes/blocks.js +18 -15
  16. data/dist/ruby/nodes/calls.js +33 -30
  17. data/dist/ruby/nodes/case.js +8 -8
  18. data/dist/ruby/nodes/class.js +13 -13
  19. data/dist/ruby/nodes/commands.js +36 -22
  20. data/dist/ruby/nodes/conditionals.js +56 -52
  21. data/dist/ruby/nodes/constants.js +10 -13
  22. data/dist/ruby/nodes/flow.js +39 -46
  23. data/dist/ruby/nodes/hashes.js +26 -30
  24. data/dist/ruby/nodes/heredocs.js +9 -9
  25. data/dist/ruby/nodes/hooks.js +2 -2
  26. data/dist/ruby/nodes/ints.js +5 -5
  27. data/dist/ruby/nodes/lambdas.js +7 -6
  28. data/dist/ruby/nodes/loops.js +26 -24
  29. data/dist/ruby/nodes/massign.js +22 -35
  30. data/dist/ruby/nodes/methods.js +20 -40
  31. data/dist/ruby/nodes/operators.js +26 -28
  32. data/dist/ruby/nodes/params.js +31 -25
  33. data/dist/ruby/nodes/patterns.js +34 -37
  34. data/dist/ruby/nodes/regexp.js +6 -6
  35. data/dist/ruby/nodes/rescue.js +23 -22
  36. data/dist/ruby/nodes/return.js +61 -36
  37. data/dist/ruby/nodes/statements.js +24 -25
  38. data/dist/ruby/nodes/strings.js +36 -34
  39. data/dist/ruby/nodes/super.js +6 -10
  40. data/dist/ruby/nodes/undef.js +19 -14
  41. data/dist/ruby/nodes.js +47 -21
  42. data/dist/ruby/parser.js +3 -2
  43. data/dist/ruby/parser.rb +8470 -2972
  44. data/dist/ruby/printer.js +9 -71
  45. data/dist/ruby/toProc.js +33 -35
  46. data/dist/types.js +5 -1
  47. data/dist/utils/containsAssignment.js +5 -2
  48. data/dist/utils/getChildNodes.js +305 -0
  49. data/dist/utils/inlineEnsureParens.js +1 -1
  50. data/dist/utils/isEmptyBodyStmt.js +1 -1
  51. data/dist/utils/isEmptyParams.js +12 -0
  52. data/dist/utils/isEmptyStmts.js +1 -1
  53. data/dist/utils/makeCall.js +5 -4
  54. data/dist/utils/printEmptyCollection.js +3 -1
  55. data/dist/utils/skipAssignIndent.js +6 -2
  56. data/dist/utils.js +5 -3
  57. data/lib/prettier.rb +2 -1
  58. data/node_modules/prettier/bin-prettier.js +48 -18924
  59. data/node_modules/prettier/cli.js +12335 -0
  60. data/node_modules/prettier/doc.js +1306 -4755
  61. data/node_modules/prettier/index.js +37468 -57614
  62. data/node_modules/prettier/package.json +3 -2
  63. data/node_modules/prettier/parser-angular.js +2 -66
  64. data/node_modules/prettier/parser-babel.js +27 -22
  65. data/node_modules/prettier/parser-espree.js +26 -22
  66. data/node_modules/prettier/parser-flow.js +26 -22
  67. data/node_modules/prettier/parser-glimmer.js +27 -1
  68. data/node_modules/prettier/parser-graphql.js +15 -1
  69. data/node_modules/prettier/parser-html.js +21 -117
  70. data/node_modules/prettier/parser-markdown.js +61 -19
  71. data/node_modules/prettier/parser-meriyah.js +19 -22
  72. data/node_modules/prettier/parser-postcss.js +76 -22
  73. data/node_modules/prettier/parser-typescript.js +280 -22
  74. data/node_modules/prettier/parser-yaml.js +150 -15
  75. data/node_modules/prettier/third-party.js +8660 -11030
  76. data/package.json +7 -7
  77. metadata +7 -3
@@ -10,11 +10,19 @@ const { align, group, ifBreak, indent, join, line, softline } = prettier_1.defau
10
10
  function throwBadDoc(doc) {
11
11
  throw new Error(`Unknown doc ${doc}`);
12
12
  }
13
+ function reduceDocLength(sum, doc) {
14
+ // If we've hit a line, then we're going to start the counting back at 0 since
15
+ // it will be starting from the beginning of a line.
16
+ if (typeof doc === "object" && !Array.isArray(doc) && doc.type === "line") {
17
+ return 0;
18
+ }
19
+ return sum + docBreakLength(doc);
20
+ }
13
21
  // Loop through the already created doc nodes and determine the overall length
14
22
  // so that we can properly align the command arguments.
15
- function docLength(doc) {
23
+ function docBreakLength(doc) {
16
24
  if (Array.isArray(doc)) {
17
- return doc.reduce((sum, child) => sum + docLength(child), 0);
25
+ return doc.reduce(reduceDocLength, 0);
18
26
  }
19
27
  if (typeof doc === "string") {
20
28
  return doc.length;
@@ -22,16 +30,16 @@ function docLength(doc) {
22
30
  switch (doc.type) {
23
31
  case "concat":
24
32
  case "fill":
25
- return doc.parts.reduce((sum, child) => sum + docLength(child), 0);
33
+ return doc.parts.reduce(reduceDocLength, 0);
26
34
  case "align":
27
35
  case "group":
28
36
  case "indent":
29
37
  case "line-suffix":
30
- return docLength(doc.contents);
38
+ return docBreakLength(doc.contents);
31
39
  case "if-break":
32
- return docLength(doc.flatContents);
40
+ return docBreakLength(doc.breakContents);
33
41
  case "line":
34
- return doc.soft ? 0 : 1;
42
+ return 0;
35
43
  case "break-parent":
36
44
  case "cursor":
37
45
  case "indent-if-break":
@@ -44,10 +52,10 @@ function docLength(doc) {
44
52
  }
45
53
  }
46
54
  function hasDef(node) {
47
- return (node.body[1].type === "args_add_block" &&
48
- node.body[1].body[0].type === "args" &&
49
- node.body[1].body[0].body[0] &&
50
- ["def", "defs"].includes(node.body[1].body[0].body[0].type));
55
+ return (node.args.type === "args_add_block" &&
56
+ node.args.args.type === "args" &&
57
+ node.args.args.parts[0] &&
58
+ ["def", "defs"].includes(node.args.args.parts[0].type));
51
59
  }
52
60
  // Very special handling case for rspec matchers. In general with rspec matchers
53
61
  // you expect to see something like:
@@ -63,19 +71,25 @@ function hasDef(node) {
63
71
  // In this case the arguments are aligned to the left side as opposed to being
64
72
  // aligned with the `receive` call.
65
73
  function skipArgsAlign(node) {
66
- return ["to", "not_to", "to_not"].includes(node.body[2].body);
74
+ return ["to", "not_to", "to_not"].includes(node.message.value);
67
75
  }
68
76
  // If there is a ternary argument to a command and it's going to get broken
69
77
  // into multiple lines, then we're going to have to use parentheses around the
70
78
  // command in order to make sure operator precedence doesn't get messed up.
71
79
  function hasTernaryArg(node) {
72
- return node.body[0].body.some((child) => child.type === "ifop");
80
+ var _a;
81
+ switch (node.type) {
82
+ case "args":
83
+ return node.parts.some((child) => child.type === "ifop");
84
+ case "args_add_block":
85
+ return hasTernaryArg(node.args) || ((_a = node.block) === null || _a === void 0 ? void 0 : _a.type) === "ifop";
86
+ }
73
87
  }
74
88
  const printCommand = (path, opts, print) => {
75
89
  const node = path.getValue();
76
- const command = path.call(print, "body", 0);
77
- const joinedArgs = join([",", line], path.call(print, "body", 1));
78
- const hasTernary = hasTernaryArg(node.body[1]);
90
+ const command = path.call(print, "message");
91
+ const joinedArgs = join([",", line], path.call(print, "args"));
92
+ const hasTernary = hasTernaryArg(node.args);
79
93
  let breakArgs;
80
94
  if (hasTernary) {
81
95
  breakArgs = indent([softline, joinedArgs]);
@@ -84,7 +98,7 @@ const printCommand = (path, opts, print) => {
84
98
  breakArgs = joinedArgs;
85
99
  }
86
100
  else {
87
- breakArgs = align(docLength(command) + 1, joinedArgs);
101
+ breakArgs = align(docBreakLength(command) + 1, joinedArgs);
88
102
  }
89
103
  return group(ifBreak([
90
104
  command,
@@ -97,16 +111,16 @@ exports.printCommand = printCommand;
97
111
  const printCommandCall = (path, opts, print) => {
98
112
  const node = path.getValue();
99
113
  const parts = [
100
- path.call(print, "body", 0),
114
+ path.call(print, "receiver"),
101
115
  (0, utils_1.makeCall)(path, opts, print),
102
- path.call(print, "body", 2)
116
+ path.call(print, "message")
103
117
  ];
104
- if (!node.body[3]) {
118
+ if (!node.args) {
105
119
  return parts;
106
120
  }
107
- const argDocs = join([",", line], path.call(print, "body", 3));
121
+ const argDocs = join([",", line], path.call(print, "args"));
108
122
  let breakDoc;
109
- if (hasTernaryArg(node.body[3])) {
123
+ if (hasTernaryArg(node.args)) {
110
124
  breakDoc = parts.concat("(", indent([softline, argDocs]), softline, ")");
111
125
  parts.push(" ");
112
126
  }
@@ -116,7 +130,7 @@ const printCommandCall = (path, opts, print) => {
116
130
  }
117
131
  else {
118
132
  parts.push(" ");
119
- breakDoc = parts.concat(align(docLength(parts), argDocs));
133
+ breakDoc = parts.concat(align(docBreakLength(parts), argDocs));
120
134
  }
121
135
  const joinedDoc = parts.concat(argDocs);
122
136
  return group(ifBreak(breakDoc, joinedDoc));
@@ -16,9 +16,9 @@ function containsSingleConditional(stmts) {
16
16
  function printWithAddition(keyword, path, print, breaking) {
17
17
  return [
18
18
  `${keyword} `,
19
- align(keyword.length + 1, path.call(print, "body", 0)),
20
- indent([softline, path.call(print, "body", 1)]),
21
- [softline, path.call(print, "body", 2)],
19
+ align(keyword.length + 1, path.call(print, "pred")),
20
+ indent([softline, path.call(print, "stmts")]),
21
+ [softline, path.call(print, "cons")],
22
22
  [softline, "end"],
23
23
  breaking ? breakParent : ""
24
24
  ];
@@ -54,26 +54,30 @@ function printTernaryClauses(keyword, truthyClause, falsyClause) {
54
54
  // Handles ternary nodes. If it does not fit on one line, then we break out into
55
55
  // an if/else statement. Otherwise we remain as a ternary.
56
56
  const printTernary = (path, _opts, print) => {
57
- const [predicate, truthyClause, falsyClause] = path.map(print, "body");
58
- const ternaryClauses = printTernaryClauses("if", truthyClause, falsyClause);
57
+ const predicateDoc = path.call(print, "pred");
58
+ const truthyDoc = path.call(print, "tthy");
59
+ const falsyDoc = path.call(print, "flsy");
59
60
  return group(ifBreak([
60
61
  "if ",
61
- align(3, predicate),
62
- indent([softline, truthyClause]),
62
+ align(3, predicateDoc),
63
+ indent([softline, truthyDoc]),
63
64
  [softline, "else"],
64
- indent([softline, falsyClause]),
65
+ indent([softline, falsyDoc]),
65
66
  [softline, "end"]
66
- ], [predicate, " ? ", ...ternaryClauses]));
67
+ ], [predicateDoc, " ? ", ...printTernaryClauses("if", truthyDoc, falsyDoc)]));
67
68
  };
68
69
  exports.printTernary = printTernary;
70
+ function isModifier(node) {
71
+ return node.type === "if_mod" || node.type === "unless_mod";
72
+ }
69
73
  // Prints an `if_mod` or `unless_mod` node. Because it was previously in the
70
74
  // modifier form, we're guaranteed to not have an additional node, so we can
71
75
  // just work with the predicate and the body.
72
- function printSingle(keyword, modifier = false) {
76
+ function printSingle(keyword) {
73
77
  return function printSingleWithKeyword(path, { rubyModifier }, print) {
74
- const [, statementsNode] = path.getValue().body;
75
- const predicateDoc = path.call(print, "body", 0);
76
- const statementsDoc = path.call(print, "body", 1);
78
+ const node = path.getValue();
79
+ const predicateDoc = path.call(print, "pred");
80
+ const statementsDoc = path.call(print, isModifier(node) ? "stmt" : "stmts");
77
81
  const multilineParts = [
78
82
  `${keyword} `,
79
83
  align(keyword.length + 1, predicateDoc),
@@ -84,22 +88,21 @@ function printSingle(keyword, modifier = false) {
84
88
  // If we do not allow modifier form conditionals or there are comments
85
89
  // inside of the body of the conditional, then we must print in the
86
90
  // multiline form.
87
- if (!rubyModifier ||
88
- (!modifier && statementsNode.body[0].comments)) {
91
+ if (!rubyModifier || (!isModifier(node) && node.stmts.body[0].comments)) {
89
92
  return [multilineParts, breakParent];
90
93
  }
91
94
  const inline = (0, utils_1.inlineEnsureParens)(path, [
92
- path.call(print, "body", 1),
95
+ statementsDoc,
93
96
  ` ${keyword} `,
94
- path.call(print, "body", 0)
97
+ predicateDoc
95
98
  ]);
96
- // An expression with a conditional modifier (expression if true), the
99
+ // With an expression with a conditional modifier (expression if true), the
97
100
  // conditional body is parsed before the predicate expression, meaning that
98
101
  // if the parser encountered a variable declaration, it would initialize
99
102
  // that variable first before evaluating the predicate expression. That
100
103
  // parse order means the difference between a NameError or not. #591
101
104
  // https://docs.ruby-lang.org/en/2.0.0/syntax/control_expressions_rdoc.html#label-Modifier+if+and+unless
102
- if (modifier && (0, utils_1.containsAssignment)(statementsNode)) {
105
+ if (isModifier(node) && (0, utils_1.containsAssignment)(node.stmt)) {
103
106
  return inline;
104
107
  }
105
108
  return group(ifBreak(multilineParts, inline));
@@ -144,7 +147,7 @@ function canTernaryStmts(stmts) {
144
147
  const stmt = stmts.body[0];
145
148
  // If the user is using one of the lower precedence "and" or "or" operators,
146
149
  // then we can't use a ternary expression as it would break the flow control.
147
- if (stmt.type === "binary" && ["and", "or"].includes(stmt.body[1])) {
150
+ if (stmt.type === "binary" && ["and", "or"].includes(stmt.op)) {
148
151
  return false;
149
152
  }
150
153
  // Check against the blocklist of statement types that are not allowed to be
@@ -157,55 +160,56 @@ function canTernaryStmts(stmts) {
157
160
  // additional node must have only one statement, and that statement list must
158
161
  // pass the `canTernaryStmts` check.
159
162
  function canTernary(path) {
160
- const [predicate, stmts, addition] = path.getValue().body;
161
- return (!["assign", "opassign", "command_call", "command"].includes(predicate.type) &&
162
- addition &&
163
- addition.type === "else" &&
164
- [stmts, addition.body[0]].every(canTernaryStmts));
163
+ const node = path.getValue();
164
+ return (!["assign", "opassign", "command_call", "command"].includes(node.pred.type) &&
165
+ node.cons &&
166
+ node.cons.type === "else" &&
167
+ canTernaryStmts(node.stmts) &&
168
+ canTernaryStmts(node.cons.stmts));
165
169
  }
166
170
  // A normalized print function for both `if` and `unless` nodes.
167
171
  function printConditional(keyword) {
168
- return (path, opts, print) => {
172
+ return function printConditionalWithKeyword(path, opts, print) {
169
173
  if (canTernary(path)) {
170
174
  let ternaryParts = [
171
- path.call(print, "body", 0),
175
+ path.call(print, "pred"),
172
176
  " ? ",
173
- ...printTernaryClauses(keyword, path.call(print, "body", 1), path.call(print, "body", 2, "body", 0))
177
+ ...printTernaryClauses(keyword, path.call(print, "stmts"), path.call(print, "cons", "stmts"))
174
178
  ];
175
179
  if (["binary", "call"].includes(path.getParentNode().type)) {
176
180
  ternaryParts = ["(", ...ternaryParts, ")"];
177
181
  }
178
182
  return group(ifBreak(printWithAddition(keyword, path, print, false), ternaryParts));
179
183
  }
180
- const [predicate, statements, addition] = path.getValue().body;
184
+ const node = path.getValue();
181
185
  // If there's an additional clause that wasn't matched earlier, we know we
182
186
  // can't go for the inline option.
183
- if (addition) {
187
+ if (node.cons) {
184
188
  return group(printWithAddition(keyword, path, print, true));
185
189
  }
186
- // If the body of the conditional is empty, then we explicitly have to use the
187
- // block form.
188
- if ((0, utils_1.isEmptyStmts)(statements)) {
190
+ // If the body of the conditional is empty, then we explicitly have to use
191
+ // the block form.
192
+ if ((0, utils_1.isEmptyStmts)(node.stmts)) {
189
193
  return [
190
194
  `${keyword} `,
191
- align(keyword.length + 1, path.call(print, "body", 0)),
195
+ align(keyword.length + 1, path.call(print, "pred")),
192
196
  hardline,
193
197
  "end"
194
198
  ];
195
199
  }
196
200
  // Two situations in which we need to use the block form:
197
201
  //
198
- // 1. If the predicate of the conditional contains an assignment, then we can't
199
- // know for sure that it doesn't impact the body of the conditional.
202
+ // 1. If the predicate of the conditional contains an assignment, then we
203
+ // can't know for sure that it doesn't impact the body of the conditional.
200
204
  //
201
- // 2. If the conditional contains just another conditional, then collapsing it
202
- // would result in double modifiers on the same line.
203
- if ((0, utils_1.containsAssignment)(predicate) ||
204
- containsSingleConditional(statements)) {
205
+ // 2. If the conditional contains just another conditional, then collapsing
206
+ // it would result in double modifiers on the same line.
207
+ if ((0, utils_1.containsAssignment)(node.pred) ||
208
+ containsSingleConditional(node.stmts)) {
205
209
  return [
206
210
  `${keyword} `,
207
- align(keyword.length + 1, path.call(print, "body", 0)),
208
- indent([hardline, path.call(print, "body", 1)]),
211
+ align(keyword.length + 1, path.call(print, "pred")),
212
+ indent([hardline, path.call(print, "stmts")]),
209
213
  hardline,
210
214
  "end"
211
215
  ];
@@ -214,29 +218,29 @@ function printConditional(keyword) {
214
218
  };
215
219
  }
216
220
  const printElse = (path, opts, print) => {
217
- const stmts = path.getValue().body[0];
221
+ const node = path.getValue();
218
222
  return [
219
- stmts.body.length === 1 && stmts.body[0].type === "command"
223
+ node.stmts.body.length === 1 && node.stmts.body[0].type === "command"
220
224
  ? breakParent
221
225
  : "",
222
226
  "else",
223
- indent([softline, path.call(print, "body", 0)])
227
+ indent([softline, path.call(print, "stmts")])
224
228
  ];
225
229
  };
226
230
  exports.printElse = printElse;
227
231
  const printElsif = (path, opts, print) => {
228
- const [, , addition] = path.getValue().body;
232
+ const node = path.getValue();
229
233
  const parts = [
230
- group(["elsif ", align("elsif".length - 1, path.call(print, "body", 0))]),
231
- indent([hardline, path.call(print, "body", 1)])
234
+ group(["elsif ", align("elsif".length - 1, path.call(print, "pred"))]),
235
+ indent([hardline, path.call(print, "stmts")])
232
236
  ];
233
- if (addition) {
234
- parts.push(group([hardline, path.call(print, "body", 2)]));
237
+ if (node.cons) {
238
+ parts.push(group([hardline, path.call(print, "cons")]));
235
239
  }
236
240
  return group(parts);
237
241
  };
238
242
  exports.printElsif = printElsif;
239
243
  exports.printIf = printConditional("if");
240
- exports.printIfModifier = printSingle("if", true);
244
+ exports.printIfModifier = printSingle("if");
241
245
  exports.printUnless = printConditional("unless");
242
- exports.printUnlessModifier = printSingle("unless", true);
246
+ exports.printUnlessModifier = printSingle("unless");
@@ -6,19 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.printTopConst = exports.printField = exports.printDefined = exports.printConstRef = exports.printConstPath = void 0;
7
7
  const prettier_1 = __importDefault(require("../../prettier"));
8
8
  const utils_1 = require("../../utils");
9
- const { group, indent, join, softline } = prettier_1.default;
10
- const printConstPath = (path, opts, print) => {
11
- return join("::", path.map(print, "body"));
12
- };
9
+ const { group, indent, softline } = prettier_1.default;
10
+ const printConstPath = (path, opts, print) => [path.call(print, "parent"), "::", path.call(print, "constant")];
13
11
  exports.printConstPath = printConstPath;
14
- const printConstRef = (path, opts, print) => {
15
- return path.call(print, "body", 0);
16
- };
12
+ const printConstRef = (path, opts, print) => path.call(print, "constant");
17
13
  exports.printConstRef = printConstRef;
18
14
  const printDefined = (path, opts, print) => {
19
15
  return group([
20
16
  "defined?(",
21
- indent([softline, path.call(print, "body", 0)]),
17
+ indent([softline, path.call(print, "value")]),
22
18
  softline,
23
19
  ")"
24
20
  ]);
@@ -26,13 +22,14 @@ const printDefined = (path, opts, print) => {
26
22
  exports.printDefined = printDefined;
27
23
  const printField = (path, opts, print) => {
28
24
  return group([
29
- path.call(print, "body", 0),
25
+ path.call(print, "parent"),
30
26
  (0, utils_1.makeCall)(path, opts, print),
31
- path.call(print, "body", 2)
27
+ path.call(print, "name")
32
28
  ]);
33
29
  };
34
30
  exports.printField = printField;
35
- const printTopConst = (path, opts, print) => {
36
- return ["::", path.call(print, "body", 0)];
37
- };
31
+ const printTopConst = (path, opts, print) => [
32
+ "::",
33
+ path.call(print, "constant")
34
+ ];
38
35
  exports.printTopConst = printTopConst;
@@ -5,15 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.printYield0 = exports.printYield = exports.printNext = exports.printBreak = void 0;
7
7
  const prettier_1 = __importDefault(require("../../prettier"));
8
- const utils_1 = require("../../utils");
9
8
  const { join } = prettier_1.default;
10
- function nodeDive(node, steps) {
11
- let current = node;
12
- steps.forEach((step) => {
13
- current = current[step];
14
- });
15
- return current;
16
- }
9
+ // If there are parentheses around these nodes, then we can't skip printing them
10
+ // without changing the semantic meaning of the statement.
17
11
  const unskippableParens = [
18
12
  "if_mod",
19
13
  "rescue_mod",
@@ -21,46 +15,45 @@ const unskippableParens = [
21
15
  "until_mod",
22
16
  "while_mod"
23
17
  ];
24
- function maybeHandleParens(path, print, keyword, steps) {
25
- const node = nodeDive(path.getValue(), steps);
26
- if (node.type !== "paren") {
27
- return null;
28
- }
29
- const stmts = node.body[0].body;
30
- if (stmts.length === 1 && !unskippableParens.includes(stmts[0].type)) {
31
- return [`${keyword} `, path.call(print, ...steps, "body", 0)];
32
- }
33
- return [keyword, path.call(print, ...steps)];
18
+ function printFlowControl(keyword) {
19
+ return function printFlowControlWithKeyword(path, opts, print) {
20
+ const node = path.getValue();
21
+ // If we don't have any arguments to the keyword, then it's always going to
22
+ // come in as an args node, in which case we can just print the keyword.
23
+ if (node.args.type === "args") {
24
+ return keyword;
25
+ }
26
+ // Special handling if we've got parentheses on this call to the keyword. If
27
+ // we do and we can skip them, then we will. If we don't, then we'll print
28
+ // them right after the keyword with no space.
29
+ const paren = node.args.args.type === "args" && node.args.args.parts[0];
30
+ if (paren && paren.type === "paren") {
31
+ const stmts = paren.cnts.body;
32
+ // Here we're checking if we can skip past the parentheses entirely.
33
+ if (stmts.length === 1 && !unskippableParens.includes(stmts[0].type)) {
34
+ return [
35
+ `${keyword} `,
36
+ path.call(print, "args", "args", "parts", 0, "cnts")
37
+ ];
38
+ }
39
+ // Here we know we can't, so just printing out the parentheses as normal.
40
+ return [keyword, path.call(print, "args", "args", "parts", 0)];
41
+ }
42
+ // If we didn't hit the super special handling, then we're just going to
43
+ // print out the arguments to the keyword like normal.
44
+ return [`${keyword} `, join(", ", path.call(print, "args"))];
45
+ };
34
46
  }
35
- const printBreak = (path, opts, print) => {
36
- const content = path.getValue().body[0];
37
- if (content.body.length === 0) {
38
- return "break";
39
- }
40
- const steps = ["body", 0, "body", 0, "body", 0];
41
- return (maybeHandleParens(path, print, "break", steps) || [
42
- "break ",
43
- join(", ", path.call(print, "body", 0))
44
- ]);
45
- };
46
- exports.printBreak = printBreak;
47
- const printNext = (path, opts, print) => {
48
- const args = path.getValue().body[0].body[0];
49
- if (!args) {
50
- return "next";
51
- }
52
- const steps = ["body", 0, "body", 0, "body", 0];
53
- return (maybeHandleParens(path, print, "next", steps) || [
54
- "next ",
55
- join(", ", path.call(print, "body", 0))
56
- ]);
57
- };
58
- exports.printNext = printNext;
47
+ exports.printBreak = printFlowControl("break");
48
+ exports.printNext = printFlowControl("next");
59
49
  const printYield = (path, opts, print) => {
60
- if (path.getValue().body[0].type === "paren") {
61
- return ["yield", path.call(print, "body", 0)];
50
+ const node = path.getValue();
51
+ const argsDoc = path.call(print, "args");
52
+ if (node.args.type === "paren") {
53
+ return ["yield", argsDoc];
62
54
  }
63
- return ["yield ", join(", ", path.call(print, "body", 0))];
55
+ return ["yield ", join(", ", argsDoc)];
64
56
  };
65
57
  exports.printYield = printYield;
66
- exports.printYield0 = (0, utils_1.literal)("yield");
58
+ const printYield0 = (path) => path.getValue().value;
59
+ exports.printYield0 = printYield0;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.printHash = exports.printHashContents = exports.printAssocSplat = exports.printAssocNew = void 0;
6
+ exports.printHash = exports.printHashContents = exports.printAssocSplat = exports.printAssoc = void 0;
7
7
  const prettier_1 = __importDefault(require("../../prettier"));
8
8
  const utils_1 = require("../../utils");
9
9
  const { group, ifBreak, indent, join, line } = prettier_1.default;
@@ -18,19 +18,19 @@ const { group, ifBreak, indent, join, line } = prettier_1.default;
18
18
  // This function represents that check, as it determines if it can convert the
19
19
  // symbol node into a hash label.
20
20
  function isValidHashLabel(symbolLiteral) {
21
- const label = symbolLiteral.body[0].body;
21
+ const label = symbolLiteral.value.value;
22
22
  return label.match(/^[_A-Za-z]/) && !label.endsWith("=");
23
23
  }
24
24
  function canUseHashLabels(contentsNode) {
25
- return contentsNode.body.every((assocNode) => {
25
+ return contentsNode.assocs.every((assocNode) => {
26
26
  if (assocNode.type === "assoc_splat") {
27
27
  return true;
28
28
  }
29
- switch (assocNode.body[0].type) {
30
- case "@label":
29
+ switch (assocNode.key.type) {
30
+ case "label":
31
31
  return true;
32
32
  case "symbol_literal":
33
- return isValidHashLabel(assocNode.body[0]);
33
+ return isValidHashLabel(assocNode.key);
34
34
  case "dyna_symbol":
35
35
  return true;
36
36
  default:
@@ -41,12 +41,10 @@ function canUseHashLabels(contentsNode) {
41
41
  const printHashKeyLabel = (path, print) => {
42
42
  const node = path.getValue();
43
43
  switch (node.type) {
44
- case "@label":
44
+ case "label":
45
45
  return print(path);
46
- case "symbol_literal": {
47
- const nodePath = path;
48
- return [nodePath.call(print, "body", 0), ":"];
49
- }
46
+ case "symbol_literal":
47
+ return [path.call(print, "value"), ":"];
50
48
  case "dyna_symbol":
51
49
  return [print(path), ":"];
52
50
  default:
@@ -58,7 +56,7 @@ const printHashKeyLabel = (path, print) => {
58
56
  const printHashKeyRocket = (path, print) => {
59
57
  const node = path.getValue();
60
58
  let doc = print(path);
61
- if (node.type === "@label") {
59
+ if (node.type === "label") {
62
60
  const sDoc = doc; // since we know this is a label
63
61
  doc = [":", sDoc.slice(0, sDoc.length - 1)];
64
62
  }
@@ -67,18 +65,18 @@ const printHashKeyRocket = (path, print) => {
67
65
  }
68
66
  return [doc, " =>"];
69
67
  };
70
- const printAssocNew = (path, opts, print) => {
71
- const [keyNode, valueNode] = path.getValue().body;
68
+ const printAssoc = (path, opts, print) => {
69
+ const node = path.getValue();
72
70
  const { keyPrinter } = path.getParentNode();
73
- const parts = [path.call((keyPath) => keyPrinter(keyPath, print), "body", 0)];
74
- const valueDoc = path.call(print, "body", 1);
71
+ const parts = [path.call((keyPath) => keyPrinter(keyPath, print), "key")];
72
+ const valueDoc = path.call(print, "value");
75
73
  // If we're printing a child hash then we want it to break along with its
76
74
  // parent hash, so we don't group the parts.
77
- if (valueNode.type === "hash") {
75
+ if (node.value.type === "hash") {
78
76
  parts.push(" ", valueDoc);
79
77
  return parts;
80
78
  }
81
- if (!(0, utils_1.skipAssignIndent)(valueNode) || keyNode.comments) {
79
+ if (!(0, utils_1.skipAssignIndent)(node.value) || node.key.comments) {
82
80
  parts.push(indent([line, valueDoc]));
83
81
  }
84
82
  else {
@@ -86,10 +84,8 @@ const printAssocNew = (path, opts, print) => {
86
84
  }
87
85
  return group(parts);
88
86
  };
89
- exports.printAssocNew = printAssocNew;
90
- const printAssocSplat = (path, opts, print) => {
91
- return ["**", path.call(print, "body", 0)];
92
- };
87
+ exports.printAssoc = printAssoc;
88
+ const printAssocSplat = (path, opts, print) => ["**", path.call(print, "value")];
93
89
  exports.printAssocSplat = printAssocSplat;
94
90
  const printHashContents = (path, opts, print) => {
95
91
  const node = path.getValue();
@@ -99,22 +95,22 @@ const printHashContents = (path, opts, print) => {
99
95
  opts.rubyHashLabel && canUseHashLabels(path.getValue())
100
96
  ? printHashKeyLabel
101
97
  : printHashKeyRocket;
102
- return join([",", line], path.map(print, "body"));
98
+ return join([",", line], path.map(print, "assocs"));
103
99
  };
104
100
  exports.printHashContents = printHashContents;
105
101
  const printHash = (path, opts, print) => {
106
- const hashNode = path.getValue();
102
+ const node = path.getValue();
107
103
  // Hashes normally have a single assoclist_from_args child node. If it's
108
104
  // missing, then it means we're dealing with an empty hash, so we can just
109
105
  // exit here and print.
110
- if (hashNode.body[0] === null) {
106
+ if (node.cnts === null) {
111
107
  return (0, utils_1.printEmptyCollection)(path, opts, "{", "}");
112
108
  }
113
- const hashDoc = [
109
+ const doc = [
114
110
  "{",
115
111
  indent([
116
112
  line,
117
- path.call(print, "body", 0),
113
+ path.call(print, "cnts"),
118
114
  (0, utils_1.getTrailingComma)(opts) ? ifBreak(",", "") : ""
119
115
  ]),
120
116
  line,
@@ -122,9 +118,9 @@ const printHash = (path, opts, print) => {
122
118
  ];
123
119
  // If we're inside another hash, then we don't want to group our contents
124
120
  // because we want this hash to break along with its parent hash.
125
- if (path.getParentNode().type === "assoc_new") {
126
- return hashDoc;
121
+ if (path.getParentNode().type === "assoc") {
122
+ return doc;
127
123
  }
128
- return group(hashDoc);
124
+ return group(doc);
129
125
  };
130
126
  exports.printHash = printHash;
@@ -8,15 +8,15 @@ const prettier_1 = __importDefault(require("../../prettier"));
8
8
  const utils_1 = require("../../utils");
9
9
  const { group, lineSuffix, join } = prettier_1.default;
10
10
  const printHeredoc = (path, opts, print) => {
11
- const { body, ending } = path.getValue();
12
- const parts = body.map((part, index) => {
13
- if (part.type !== "@tstring_content") {
14
- // In this case, the part of the string is an embedded expression
15
- return path.call(print, "body", index);
11
+ const node = path.getValue();
12
+ // Print out each part of the heredoc to its own doc node.
13
+ const parts = path.map((partPath) => {
14
+ const part = partPath.getValue();
15
+ if (part.type !== "tstring_content") {
16
+ return print(partPath);
16
17
  }
17
- // In this case, the part of the string is just regular string content
18
- return join(utils_1.literallineWithoutBreakParent, part.body.split(/\r?\n/));
19
- });
18
+ return join(utils_1.literallineWithoutBreakParent, part.value.split(/\r?\n/));
19
+ }, "parts");
20
20
  // We use a literalline break because matching indentation is required
21
21
  // for the heredoc contents and ending. If the line suffix contains a
22
22
  // break-parent, all ancestral groups are broken, and heredocs automatically
@@ -24,7 +24,7 @@ const printHeredoc = (path, opts, print) => {
24
24
  // possible, so we use a literalline without the break-parent.
25
25
  return group([
26
26
  path.call(print, "beging"),
27
- lineSuffix(group([utils_1.literallineWithoutBreakParent, ...parts, ending]))
27
+ lineSuffix(group([utils_1.literallineWithoutBreakParent, ...parts, node.ending]))
28
28
  ]);
29
29
  };
30
30
  exports.printHeredoc = printHeredoc;