prettier 2.0.0 → 2.1.0

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 (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;