prettier 1.6.1 → 2.0.0.pre.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +316 -293
  3. data/CONTRIBUTING.md +6 -9
  4. data/LICENSE +1 -1
  5. data/README.md +11 -12
  6. data/dist/haml/embed.js +53 -0
  7. data/dist/haml/parser.js +31 -0
  8. data/{src → dist}/haml/parser.rb +0 -0
  9. data/dist/haml/printer.js +336 -0
  10. data/dist/parser/getInfo.js +17 -0
  11. data/{src → dist}/parser/netcat.js +1 -0
  12. data/dist/parser/parseSync.js +128 -0
  13. data/dist/parser/server.rb +140 -0
  14. data/dist/plugin.js +143 -0
  15. data/dist/prettier.js +15 -0
  16. data/dist/rbs/parser.js +34 -0
  17. data/{src → dist}/rbs/parser.rb +0 -0
  18. data/dist/rbs/printer.js +517 -0
  19. data/dist/ruby/embed.js +110 -0
  20. data/dist/ruby/nodes/alias.js +59 -0
  21. data/{src → dist}/ruby/nodes/aref.js +26 -35
  22. data/dist/ruby/nodes/args.js +165 -0
  23. data/dist/ruby/nodes/arrays.js +126 -0
  24. data/dist/ruby/nodes/assign.js +41 -0
  25. data/dist/ruby/nodes/blocks.js +68 -0
  26. data/dist/ruby/nodes/calls.js +220 -0
  27. data/dist/ruby/nodes/case.js +50 -0
  28. data/dist/ruby/nodes/class.js +54 -0
  29. data/dist/ruby/nodes/commands.js +124 -0
  30. data/dist/ruby/nodes/conditionals.js +242 -0
  31. data/dist/ruby/nodes/constants.js +38 -0
  32. data/dist/ruby/nodes/flow.js +66 -0
  33. data/dist/ruby/nodes/hashes.js +130 -0
  34. data/dist/ruby/nodes/heredocs.js +30 -0
  35. data/dist/ruby/nodes/hooks.js +35 -0
  36. data/dist/ruby/nodes/ints.js +27 -0
  37. data/dist/ruby/nodes/lambdas.js +69 -0
  38. data/dist/ruby/nodes/loops.js +73 -0
  39. data/dist/ruby/nodes/massign.js +73 -0
  40. data/dist/ruby/nodes/methods.js +70 -0
  41. data/dist/ruby/nodes/operators.js +70 -0
  42. data/dist/ruby/nodes/params.js +89 -0
  43. data/dist/ruby/nodes/patterns.js +109 -0
  44. data/dist/ruby/nodes/regexp.js +45 -0
  45. data/dist/ruby/nodes/rescue.js +82 -0
  46. data/dist/ruby/nodes/return.js +75 -0
  47. data/dist/ruby/nodes/statements.js +111 -0
  48. data/dist/ruby/nodes/strings.js +218 -0
  49. data/dist/ruby/nodes/super.js +30 -0
  50. data/dist/ruby/nodes/undef.js +26 -0
  51. data/dist/ruby/nodes.js +151 -0
  52. data/dist/ruby/parser.js +34 -0
  53. data/{src → dist}/ruby/parser.rb +1215 -252
  54. data/dist/ruby/printer.js +125 -0
  55. data/dist/ruby/toProc.js +93 -0
  56. data/dist/types/haml.js +4 -0
  57. data/dist/types/plugin.js +3 -0
  58. data/dist/types/rbs.js +4 -0
  59. data/dist/types/ruby.js +4 -0
  60. data/dist/types/utils.js +2 -0
  61. data/dist/types.js +30 -0
  62. data/dist/utils/containsAssignment.js +15 -0
  63. data/dist/utils/getTrailingComma.js +6 -0
  64. data/dist/utils/hasAncestor.js +15 -0
  65. data/{src → dist}/utils/inlineEnsureParens.js +16 -17
  66. data/dist/utils/isEmptyBodyStmt.js +10 -0
  67. data/dist/utils/isEmptyStmts.js +10 -0
  68. data/dist/utils/literal.js +8 -0
  69. data/dist/utils/literallineWithoutBreakParent.js +8 -0
  70. data/dist/utils/makeCall.js +13 -0
  71. data/dist/utils/noIndent.js +11 -0
  72. data/dist/utils/printEmptyCollection.js +44 -0
  73. data/dist/utils/skipAssignIndent.js +15 -0
  74. data/dist/utils.js +30 -0
  75. data/node_modules/prettier/bin-prettier.js +313 -190
  76. data/node_modules/prettier/doc.js +191 -323
  77. data/node_modules/prettier/index.js +2753 -3677
  78. data/node_modules/prettier/package.json +1 -1
  79. data/node_modules/prettier/parser-angular.js +13 -14
  80. data/node_modules/prettier/parser-babel.js +7 -7
  81. data/node_modules/prettier/parser-espree.js +7 -7
  82. data/node_modules/prettier/parser-flow.js +7 -7
  83. data/node_modules/prettier/parser-glimmer.js +1 -1
  84. data/node_modules/prettier/parser-graphql.js +1 -1
  85. data/node_modules/prettier/parser-html.js +17 -17
  86. data/node_modules/prettier/parser-markdown.js +9 -9
  87. data/node_modules/prettier/parser-meriyah.js +7 -7
  88. data/node_modules/prettier/parser-postcss.js +2 -2
  89. data/node_modules/prettier/parser-typescript.js +7 -7
  90. data/node_modules/prettier/parser-yaml.js +2 -2
  91. data/node_modules/prettier/third-party.js +143 -78
  92. data/package.json +26 -18
  93. metadata +74 -67
  94. data/src/haml/embed.js +0 -87
  95. data/src/haml/parser.js +0 -23
  96. data/src/haml/printer.js +0 -438
  97. data/src/parser/parseSync.js +0 -172
  98. data/src/parser/server.rb +0 -66
  99. data/src/plugin.js +0 -148
  100. data/src/prettier.js +0 -16
  101. data/src/rbs/parser.js +0 -37
  102. data/src/rbs/printer.js +0 -643
  103. data/src/ruby/embed.js +0 -142
  104. data/src/ruby/nodes/alias.js +0 -73
  105. data/src/ruby/nodes/args.js +0 -222
  106. data/src/ruby/nodes/arrays.js +0 -162
  107. data/src/ruby/nodes/assign.js +0 -47
  108. data/src/ruby/nodes/blocks.js +0 -90
  109. data/src/ruby/nodes/calls.js +0 -246
  110. data/src/ruby/nodes/case.js +0 -65
  111. data/src/ruby/nodes/class.js +0 -64
  112. data/src/ruby/nodes/commands.js +0 -131
  113. data/src/ruby/nodes/conditionals.js +0 -282
  114. data/src/ruby/nodes/constants.js +0 -43
  115. data/src/ruby/nodes/flow.js +0 -74
  116. data/src/ruby/nodes/hashes.js +0 -155
  117. data/src/ruby/nodes/heredocs.js +0 -36
  118. data/src/ruby/nodes/hooks.js +0 -34
  119. data/src/ruby/nodes/ints.js +0 -31
  120. data/src/ruby/nodes/lambdas.js +0 -76
  121. data/src/ruby/nodes/loops.js +0 -98
  122. data/src/ruby/nodes/massign.js +0 -98
  123. data/src/ruby/nodes/methods.js +0 -74
  124. data/src/ruby/nodes/operators.js +0 -83
  125. data/src/ruby/nodes/params.js +0 -106
  126. data/src/ruby/nodes/patterns.js +0 -157
  127. data/src/ruby/nodes/regexp.js +0 -56
  128. data/src/ruby/nodes/rescue.js +0 -101
  129. data/src/ruby/nodes/return.js +0 -94
  130. data/src/ruby/nodes/statements.js +0 -142
  131. data/src/ruby/nodes/strings.js +0 -272
  132. data/src/ruby/nodes/super.js +0 -35
  133. data/src/ruby/nodes/undef.js +0 -42
  134. data/src/ruby/nodes.js +0 -34
  135. data/src/ruby/parser.js +0 -37
  136. data/src/ruby/printer.js +0 -147
  137. data/src/ruby/toProc.js +0 -105
  138. data/src/utils/containsAssignment.js +0 -11
  139. data/src/utils/getTrailingComma.js +0 -5
  140. data/src/utils/hasAncestor.js +0 -17
  141. data/src/utils/isEmptyBodyStmt.js +0 -7
  142. data/src/utils/isEmptyStmts.js +0 -11
  143. data/src/utils/literal.js +0 -7
  144. data/src/utils/literallineWithoutBreakParent.js +0 -7
  145. data/src/utils/makeCall.js +0 -14
  146. data/src/utils/noIndent.js +0 -10
  147. data/src/utils/printEmptyCollection.js +0 -49
  148. data/src/utils/skipAssignIndent.js +0 -17
  149. data/src/utils.js +0 -13
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.printCallContainer = exports.printMethodAddBlock = exports.printMethodAddArg = exports.printCall = void 0;
7
+ const prettier_1 = __importDefault(require("../../prettier"));
8
+ const utils_1 = require("../../utils");
9
+ const toProc_1 = __importDefault(require("../toProc"));
10
+ const { group, hardline, ifBreak, indent, join, softline } = prettier_1.default;
11
+ const chained = ["call", "method_add_arg", "method_add_block"];
12
+ const printCall = (path, opts, print) => {
13
+ const node = path.getValue();
14
+ const [receiverNode, , messageNode] = node.body;
15
+ const receiverDoc = path.call(print, "body", 0);
16
+ const operatorDoc = (0, utils_1.makeCall)(path, opts, print);
17
+ // You can call lambdas with a special syntax that looks like func.(*args).
18
+ // In this case, "call" is returned for the 3rd child node. We don't alter
19
+ // call syntax so if `call` is implicit, we don't print it out.
20
+ const messageDoc = messageNode === "call" ? "" : path.call(print, "body", 2);
21
+ // For certain left sides of the call nodes, we want to attach directly to
22
+ // the } or end.
23
+ if (utils_1.noIndent.includes(receiverNode.type)) {
24
+ return [receiverDoc, operatorDoc, messageDoc];
25
+ }
26
+ // The right side of the call node, as in everything including the operator
27
+ // and beyond.
28
+ let rightSideDoc = [
29
+ receiverNode.comments ? hardline : softline,
30
+ operatorDoc,
31
+ messageDoc
32
+ ];
33
+ // This is very specialized behavior wherein we group .where.not calls
34
+ // together because it looks better. For more information, see
35
+ // https://github.com/prettier/plugin-ruby/issues/862.
36
+ if (receiverNode.type === "call" &&
37
+ receiverNode.body[2] !== "call" &&
38
+ receiverNode.body[2].body === "where" &&
39
+ messageDoc === "not") {
40
+ rightSideDoc = [operatorDoc, messageDoc];
41
+ }
42
+ // Get a reference to the parent node so we can check if we're inside a chain
43
+ const parentNode = path.getParentNode();
44
+ // If our parent node is a chained node then we're not going to group the
45
+ // right side of the expression, as we want to have a nice multi-line layout.
46
+ if (chained.includes(parentNode.type) && !node.comments) {
47
+ parentNode.chain = (node.chain || 0) + 1;
48
+ parentNode.callChain = (node.callChain || 0) + 1;
49
+ parentNode.breakDoc = (node.breakDoc || [receiverDoc]).concat(rightSideDoc);
50
+ parentNode.firstReceiverType = node.firstReceiverType || receiverNode.type;
51
+ }
52
+ // If we're at the top of a chain, then we're going to print out a nice
53
+ // multi-line layout if this doesn't break into multiple lines.
54
+ if (!chained.includes(parentNode.type) &&
55
+ (node.chain || 0) >= 3 &&
56
+ node.breakDoc) {
57
+ return ifBreak(group(indent(node.breakDoc.concat(rightSideDoc))), [
58
+ receiverDoc,
59
+ group(rightSideDoc)
60
+ ]);
61
+ }
62
+ return group([receiverDoc, group(indent(rightSideDoc))]);
63
+ };
64
+ exports.printCall = printCall;
65
+ const printMethodAddArg = (path, opts, print) => {
66
+ const node = path.getValue();
67
+ const [methodNode, argNode] = node.body;
68
+ const [methodDoc, argsDoc] = path.map(print, "body");
69
+ // You can end up here if you have a method with a ? ending, presumably
70
+ // because the parser knows that it cannot be a local variable. You can also
71
+ // end up here if you are explicitly using an empty set of parentheses.
72
+ if (argsDoc.length === 0) {
73
+ // If you're using an explicit set of parentheses on something that looks
74
+ // like a constant, then we need to match that in order to maintain valid
75
+ // Ruby. For example, you could do something like Foo(), on which we would
76
+ // need to keep the parentheses to make it look like a method call.
77
+ if (methodNode.type === "fcall" && methodNode.body[0].type === "@const") {
78
+ return [methodDoc, "()"];
79
+ }
80
+ // If you're using an explicit set parentheses with the special call syntax,
81
+ // then we need to explicitly print out an extra set of parentheses. For
82
+ // example, if you call something like Foo.new.() (implicitly calling the
83
+ // #call method on a new instance of the Foo class), then we have to print
84
+ // out those parentheses, otherwise we'll end up with Foo.new.
85
+ if (methodNode.type === "call" && methodNode.body[2] === "call") {
86
+ return [methodDoc, "()"];
87
+ }
88
+ return methodDoc;
89
+ }
90
+ // This case will ONLY be hit if we can successfully turn the block into a
91
+ // to_proc call. In that case, we just explicitly add the parens around it.
92
+ if (argNode.type === "args" && argsDoc.length > 0) {
93
+ return [methodDoc, "(", ...argsDoc, ")"];
94
+ }
95
+ // Get a reference to the parent node so we can check if we're inside a chain
96
+ const parentNode = path.getParentNode();
97
+ // If our parent node is a chained node then we're not going to group the
98
+ // right side of the expression, as we want to have a nice multi-line layout.
99
+ if (chained.includes(parentNode.type) && !node.comments) {
100
+ parentNode.chain = (node.chain || 0) + 1;
101
+ parentNode.breakDoc = (node.breakDoc || [methodDoc]).concat(argsDoc);
102
+ parentNode.firstReceiverType = node.firstReceiverType;
103
+ }
104
+ // This is the threshold at which we will start to try to make a nicely
105
+ // indented call chain. For the most part, it's always 3.
106
+ let threshold = 3;
107
+ // Here, we have very specialized behavior where if we're within a sig block,
108
+ // then we're going to assume we're creating a Sorbet type signature. In that
109
+ // case, we really want the threshold to be lowered to 2 so that we create
110
+ // method chains off of any two method calls within the block. For more
111
+ // details, see
112
+ // https://github.com/prettier/plugin-ruby/issues/863.
113
+ let sigBlock = path.getParentNode(2);
114
+ if (sigBlock) {
115
+ // If we're at a do_block, then we want to go one more level up. This is
116
+ // because do_blocks have bodystmt nodes instead of just stmt nodes.
117
+ if (sigBlock.type === "do_block") {
118
+ sigBlock = path.getParentNode(3);
119
+ }
120
+ if (sigBlock.type === "method_add_block" &&
121
+ sigBlock.body[1] &&
122
+ sigBlock.body[0].type === "method_add_arg" &&
123
+ sigBlock.body[0].body[0].type === "fcall" &&
124
+ sigBlock.body[0].body[0].body[0].body === "sig") {
125
+ threshold = 2;
126
+ }
127
+ }
128
+ // If we're at the top of a chain, then we're going to print out a nice
129
+ // multi-line layout if this doesn't break into multiple lines.
130
+ if (!chained.includes(parentNode.type) &&
131
+ (node.chain || 0) >= threshold &&
132
+ node.breakDoc) {
133
+ // This is pretty specialized behavior. Basically if we're at the top of a
134
+ // chain but we've only had method calls without arguments and now we have
135
+ // arguments, then we're effectively trying to call a method with arguments
136
+ // that is nested under a bunch of stuff. So we group together to first part
137
+ // to make it so just the arguments break. This looks like, for example:
138
+ //
139
+ // config.action_dispatch.rescue_responses.merge!(
140
+ // 'ActiveRecord::ConnectionTimeoutError' => :service_unavailable,
141
+ // 'ActiveRecord::QueryCanceled' => :service_unavailable
142
+ // )
143
+ //
144
+ if (node.callChain === node.chain) {
145
+ return [group(indent(node.breakDoc)), group(argsDoc)];
146
+ }
147
+ return ifBreak(group(indent(node.breakDoc.concat(argsDoc))), [
148
+ methodDoc,
149
+ argsDoc
150
+ ]);
151
+ }
152
+ // If there are already parentheses, then we can just use the doc that's
153
+ // already printed.
154
+ if (argNode.type == "arg_paren") {
155
+ return [methodDoc, argsDoc];
156
+ }
157
+ return [methodDoc, " ", join(", ", argsDoc), " "];
158
+ };
159
+ exports.printMethodAddArg = printMethodAddArg;
160
+ const printMethodAddBlock = (path, opts, print) => {
161
+ const node = path.getValue();
162
+ const [callNode, blockNode] = node.body;
163
+ const [callDoc, blockDoc] = path.map(print, "body");
164
+ // Don't bother trying to do any kind of fancy toProc transform if the option
165
+ // is disabled.
166
+ if (opts.rubyToProc) {
167
+ const proc = (0, toProc_1.default)(path, blockNode);
168
+ if (proc && callNode.type === "call") {
169
+ return group([
170
+ path.call(print, "body", 0),
171
+ "(",
172
+ indent([softline, proc]),
173
+ [softline, ")"]
174
+ ]);
175
+ }
176
+ if (proc) {
177
+ return path.call(print, "body", 0);
178
+ }
179
+ }
180
+ // Get a reference to the parent node so we can check if we're inside a chain
181
+ const parentNode = path.getParentNode();
182
+ // If our parent node is a chained node then we're not going to group the
183
+ // right side of the expression, as we want to have a nice multi-line layout.
184
+ if (chained.includes(parentNode.type)) {
185
+ parentNode.chain = (node.chain || 0) + 1;
186
+ parentNode.breakDoc = (node.breakDoc || [callDoc]).concat(blockDoc);
187
+ parentNode.firstReceiverType = node.firstReceiverType;
188
+ }
189
+ // If we're at the top of a chain, then we're going to print out a nice
190
+ // multi-line layout if this doesn't break into multiple lines.
191
+ if (!chained.includes(parentNode.type) &&
192
+ (node.chain || 0) >= 3 &&
193
+ node.breakDoc) {
194
+ // This is pretty specialized behavior. Basically if we're at the top of a
195
+ // chain but we've only had method calls without arguments and now we have
196
+ // a method call with a block, then we're effectively trying to call a
197
+ // method with arguments that is nested under a bunch of stuff. So we group
198
+ // together to first part to make it so just the block breaks. This looks
199
+ // like, for example:
200
+ //
201
+ // Rails.application.routes.draw do
202
+ // root 'articles#index'
203
+ // resources :articles
204
+ // end
205
+ //
206
+ if (node.callChain === node.chain) {
207
+ return [group(indent(node.breakDoc)), group(blockDoc)];
208
+ }
209
+ return ifBreak(group(indent(node.breakDoc.concat(blockDoc))), [
210
+ callDoc,
211
+ blockDoc
212
+ ]);
213
+ }
214
+ return [callDoc, blockDoc];
215
+ };
216
+ exports.printMethodAddBlock = printMethodAddBlock;
217
+ const printCallContainer = (path, opts, print) => {
218
+ return path.call(print, "body", 0);
219
+ };
220
+ exports.printCallContainer = printCallContainer;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.printWhen = exports.printCase = void 0;
7
+ const prettier_1 = __importDefault(require("../../prettier"));
8
+ const { align, fill, group, hardline, indent, line } = prettier_1.default;
9
+ const printCase = (path, opts, print) => {
10
+ const parts = ["case"];
11
+ // You don't need to explicitly have something to test against in a case
12
+ // statement (without it it effectively becomes an if/elsif chain).
13
+ if (path.getValue().body[0]) {
14
+ parts.push(" ", path.call(print, "body", 0));
15
+ }
16
+ return [...parts, hardline, path.call(print, "body", 1), hardline, "end"];
17
+ };
18
+ exports.printCase = printCase;
19
+ const printWhen = (path, opts, print) => {
20
+ const [, , addition] = path.getValue().body;
21
+ // The `fill` builder command expects an array of docs alternating with
22
+ // line breaks. This is so it can loop through and determine where to break.
23
+ const preds = fill(path.call(print, "body", 0).reduce((accum, pred, index) => {
24
+ if (index === 0) {
25
+ return [pred];
26
+ }
27
+ // Pull off the last element and make it concat with a comma so that
28
+ // we can maintain alternating lines and docs.
29
+ return [
30
+ ...accum.slice(0, -1),
31
+ [accum[accum.length - 1], ","],
32
+ line,
33
+ pred
34
+ ];
35
+ }, []));
36
+ const stmts = path.call(print, "body", 1);
37
+ const parts = [["when ", align("when ".length, preds)]];
38
+ // It's possible in a when to just have empty void statements, in which case
39
+ // we would skip adding the body.
40
+ if (!stmts.every((part) => !part)) {
41
+ parts.push(indent([hardline, stmts]));
42
+ }
43
+ // This is the next clause on the case statement, either another `when` or
44
+ // an `else` clause.
45
+ if (addition) {
46
+ parts.push(hardline, path.call(print, "body", 2));
47
+ }
48
+ return group(parts);
49
+ };
50
+ exports.printWhen = printWhen;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.printSClass = exports.printModule = exports.printClass = void 0;
7
+ const prettier_1 = __importDefault(require("../../prettier"));
8
+ const utils_1 = require("../../utils");
9
+ const { group, hardline, indent } = prettier_1.default;
10
+ const printClass = (path, opts, print) => {
11
+ const [, superclass, bodystmt] = path.getValue().body;
12
+ const parts = ["class ", path.call(print, "body", 0)];
13
+ if (superclass) {
14
+ parts.push(" < ", path.call(print, "body", 1));
15
+ }
16
+ const declaration = group(parts);
17
+ if ((0, utils_1.isEmptyBodyStmt)(bodystmt)) {
18
+ return group([declaration, hardline, "end"]);
19
+ }
20
+ return group([
21
+ declaration,
22
+ indent([hardline, path.call(print, "body", 2)]),
23
+ [hardline, "end"]
24
+ ]);
25
+ };
26
+ exports.printClass = printClass;
27
+ const printModule = (path, opts, print) => {
28
+ const node = path.getValue();
29
+ const declaration = group(["module ", path.call(print, "body", 0)]);
30
+ if ((0, utils_1.isEmptyBodyStmt)(node.body[1])) {
31
+ return group([declaration, hardline, "end"]);
32
+ }
33
+ return group([
34
+ declaration,
35
+ indent([hardline, path.call(print, "body", 1)]),
36
+ hardline,
37
+ "end"
38
+ ]);
39
+ };
40
+ exports.printModule = printModule;
41
+ const printSClass = (path, opts, print) => {
42
+ const bodystmt = path.getValue().body[1];
43
+ const declaration = ["class << ", path.call(print, "body", 0)];
44
+ if ((0, utils_1.isEmptyBodyStmt)(bodystmt)) {
45
+ return group([declaration, hardline, "end"]);
46
+ }
47
+ return group([
48
+ declaration,
49
+ indent([hardline, path.call(print, "body", 1)]),
50
+ hardline,
51
+ "end"
52
+ ]);
53
+ };
54
+ exports.printSClass = printSClass;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.printCommandCall = exports.printCommand = void 0;
7
+ const prettier_1 = __importDefault(require("../../prettier"));
8
+ const utils_1 = require("../../utils");
9
+ const { align, group, ifBreak, indent, join, line, softline } = prettier_1.default;
10
+ function throwBadDoc(doc) {
11
+ throw new Error(`Unknown doc ${doc}`);
12
+ }
13
+ // Loop through the already created doc nodes and determine the overall length
14
+ // so that we can properly align the command arguments.
15
+ function docLength(doc) {
16
+ if (Array.isArray(doc)) {
17
+ return doc.reduce((sum, child) => sum + docLength(child), 0);
18
+ }
19
+ if (typeof doc === "string") {
20
+ return doc.length;
21
+ }
22
+ switch (doc.type) {
23
+ case "concat":
24
+ case "fill":
25
+ return doc.parts.reduce((sum, child) => sum + docLength(child), 0);
26
+ case "align":
27
+ case "group":
28
+ case "indent":
29
+ case "line-suffix":
30
+ return docLength(doc.contents);
31
+ case "if-break":
32
+ return docLength(doc.flatContents);
33
+ case "line":
34
+ return doc.soft ? 0 : 1;
35
+ case "break-parent":
36
+ case "cursor":
37
+ case "indent-if-break":
38
+ case "label":
39
+ case "line-suffix-boundary":
40
+ case "trim":
41
+ return 0;
42
+ default:
43
+ throwBadDoc(doc);
44
+ }
45
+ }
46
+ 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));
51
+ }
52
+ // Very special handling case for rspec matchers. In general with rspec matchers
53
+ // you expect to see something like:
54
+ //
55
+ // expect(foo).to receive(:bar).with(
56
+ // 'one',
57
+ // 'two',
58
+ // 'three',
59
+ // 'four',
60
+ // 'five'
61
+ // )
62
+ //
63
+ // In this case the arguments are aligned to the left side as opposed to being
64
+ // aligned with the `receive` call.
65
+ function skipArgsAlign(path) {
66
+ return ["to", "not_to"].includes(path.getValue().body[2].body);
67
+ }
68
+ // If there is a ternary argument to a command and it's going to get broken
69
+ // into multiple lines, then we're going to have to use parentheses around the
70
+ // command in order to make sure operator precedence doesn't get messed up.
71
+ function hasTernaryArg(node) {
72
+ return node.body[0].body.some((child) => child.type === "ifop");
73
+ }
74
+ const printCommand = (path, opts, print) => {
75
+ 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]);
79
+ let breakArgs;
80
+ if (hasTernary) {
81
+ breakArgs = indent([softline, joinedArgs]);
82
+ }
83
+ else if (hasDef(node)) {
84
+ breakArgs = joinedArgs;
85
+ }
86
+ else {
87
+ breakArgs = align(docLength(command) + 1, joinedArgs);
88
+ }
89
+ return group(ifBreak([
90
+ command,
91
+ hasTernary ? "(" : " ",
92
+ breakArgs,
93
+ hasTernary ? [softline, ")"] : ""
94
+ ], [command, " ", joinedArgs]));
95
+ };
96
+ exports.printCommand = printCommand;
97
+ const printCommandCall = (path, opts, print) => {
98
+ const node = path.getValue();
99
+ const parts = [
100
+ path.call(print, "body", 0),
101
+ (0, utils_1.makeCall)(path, opts, print),
102
+ path.call(print, "body", 2)
103
+ ];
104
+ if (!node.body[3]) {
105
+ return parts;
106
+ }
107
+ const argDocs = join([",", line], path.call(print, "body", 3));
108
+ let breakDoc;
109
+ if (hasTernaryArg(node.body[3])) {
110
+ breakDoc = parts.concat("(", indent([softline, argDocs]), softline, ")");
111
+ parts.push(" ");
112
+ }
113
+ else if (skipArgsAlign(path)) {
114
+ parts.push(" ");
115
+ breakDoc = parts.concat(argDocs);
116
+ }
117
+ else {
118
+ parts.push(" ");
119
+ breakDoc = parts.concat(align(docLength(parts), argDocs));
120
+ }
121
+ const joinedDoc = parts.concat(argDocs);
122
+ return group(ifBreak(breakDoc, joinedDoc));
123
+ };
124
+ exports.printCommandCall = printCommandCall;