prettier 1.1.0 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0110d43bf561f7af177d93dce16dd6c8802bff3eb5c6603f6b72460903186b43
4
- data.tar.gz: 48dd261628c7127b3baca0c6934c21993b68831c6d545494967642f5783e3d16
3
+ metadata.gz: 3c6028bdf8198f8cfdd43bdb8d8b577e7a3bae5aaa108af45e0ee065d0b373b3
4
+ data.tar.gz: 90847afd8a74ba465b5a1bcc3dcfdc146ce57c01df77f1e3fa8c04a8b254c870
5
5
  SHA512:
6
- metadata.gz: 2caa7e2cb715c7a3c1124210b1a2efa064425ef4b2075abd84b7092e28eae67c66fc1aabf93cd6c5493b86c5c735fe9965c9f0f347be4b57f5690f74690d79b4
7
- data.tar.gz: 16f4abe1b2ca8099660cd22a541bac6a220f661db879bf9742e85645abfe0cbf36146872c6dfe33af30bc5c8b303144720abe5233d4a1748390a7ff587e8c005
6
+ metadata.gz: d99e6fefc109919be2317805e2462c0f38d2cfc7b005df3b200ea9b29ff2ac6f4438617580df94ae58c95a0df21717d87025b9ed6301e35c62fd1b84be63f321
7
+ data.tar.gz: 97353a101ef9256d63035e8838c32435816a84f735dc9aaf40a6f62b69e699249acbb2cc51ea4075802f848368712fca11ba54d8b5203392050199b1cc1f5f13
@@ -6,6 +6,55 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.2.4] - 2021-01-03
10
+
11
+ ### Added
12
+
13
+ - [@andyw8] - Explain usage with Rubocop, as well as shipping a rubocop.yml config.
14
+
15
+ ### Changed
16
+
17
+ - [@kddeisz] - Reduce JSON size passing from Ruby process to node process by changing `char_start` -> `sc`, `char_end` -> `ec`, `start` -> `sl`, `end` -> `el`.
18
+ - [@kddeisz] - Up the max buffer size between the Ruby and node processes to 15K.
19
+
20
+ ## [1.2.3] - 2021-01-02
21
+
22
+ ### Changed
23
+
24
+ - [@lukyth], [@kddeisz] - Ensure if a ternary breaks into an `if..else..end` within a `command_call` node that parentheses are added.
25
+ - [@AlanFoster], [@kddeisz] - Ensure you consume the optional `do` keyword on `while` and `until` loops so that it doesn't confuse the parser.
26
+ - [@AlanFoster], [@kddeisz] - Ensure key-value pairs split on line when the key has a comment attached within a hash.
27
+ - [@AlanFoster], [@kddeisz] - Fix for `for` loops that have multiple index variables.
28
+ - [@AlanFoster], [@kddeisz] - Fix parsing very large files by reducing the size of the JSON output from the parser.
29
+ - [@AlanFoster], [@kddeisz] - Ensure you don't skip parentheses if you're returning a value with the `not` unary operator.
30
+
31
+ ## [1.2.2] - 2021-01-01
32
+
33
+ ### Changed
34
+
35
+ - [@nathan-beam] - Gem does not work with CMD/Powershell.
36
+ - [@blampe], [@kddeisz] - Comments inside keyword parameters in method declarations are not printed.
37
+ - [@blampe], [@kddeisz] - `command_call` nodes with unary operators incorrectly parse their operator.
38
+ - [@blampe], [@kddeisz] - Returning multiple values where the first has parentheses was incorrectly removing the remaining values.
39
+ - [@johncsnyder], [@kddeisz] - Call chains whose left-most receiver is a no-indent expression should not indent their entire chain.
40
+
41
+ ## [1.2.1] - 2020-12-27
42
+
43
+ ### Changed
44
+
45
+ - [@kddeisz] - Handle single-line method definitions with parameters.
46
+ - [@kddeisz] - Handle hash and array patterns nested within find patterns.
47
+ - [@kddeisz] - Handle rightward assignment.
48
+ - [@kddeisz] - Handle find patterns with named boundaries.
49
+ - [@kddeisz] - Handle rightward assignment in conditionals.
50
+
51
+ ## [1.2.0] - 2020-12-26
52
+
53
+ ### Added
54
+
55
+ - [@kddeisz] - Support for the `fndptn` node for Ruby 3.0 pattern matching.
56
+ - [@kddeisz] - Support for Ruby 3.0+ single-line method definitions.
57
+
9
58
  ## [1.1.0] - 2020-12-20
10
59
 
11
60
  ### Added
@@ -971,7 +1020,11 @@ would previously result in `array[]`, but now prints properly.
971
1020
 
972
1021
  - Initial release 🎉
973
1022
 
974
- [unreleased]: https://github.com/prettier/plugin-ruby/compare/v1.1.0...HEAD
1023
+ [unreleased]: https://github.com/prettier/plugin-ruby/compare/v1.2.3...HEAD
1024
+ [1.2.3]: https://github.com/prettier/plugin-ruby/compare/v1.2.2...v1.2.3
1025
+ [1.2.2]: https://github.com/prettier/plugin-ruby/compare/v1.2.1...v1.2.2
1026
+ [1.2.1]: https://github.com/prettier/plugin-ruby/compare/v1.2.0...v1.2.1
1027
+ [1.2.0]: https://github.com/prettier/plugin-ruby/compare/v1.1.0...v1.2.0
975
1028
  [1.1.0]: https://github.com/prettier/plugin-ruby/compare/v1.0.1...v1.1.0
976
1029
  [1.0.1]: https://github.com/prettier/plugin-ruby/compare/v1.0.0...v1.0.1
977
1030
  [1.0.0]: https://github.com/prettier/plugin-ruby/compare/v1.0.0-rc2...v1.0.0
@@ -1032,6 +1085,7 @@ would previously result in `array[]`, but now prints properly.
1032
1085
  [@andyw8]: https://github.com/andyw8
1033
1086
  [@ashfurrow]: https://github.com/ashfurrow
1034
1087
  [@awinograd]: https://github.com/awinograd
1088
+ [@blampe]: https://github.com/blampe
1035
1089
  [@bugthing]: https://github.com/bugthing
1036
1090
  [@cbothner]: https://github.com/cbothner
1037
1091
  [@christoomey]: https://github.com/christoomey
@@ -1065,12 +1119,14 @@ would previously result in `array[]`, but now prints properly.
1065
1119
  [@kmcq]: https://github.com/kmcq
1066
1120
  [@krachtstefan]: https://github.com/krachtstefan
1067
1121
  [@localhostdotdev]: https://github.com/localhostdotdev
1122
+ [@lukyth]: https://github.com/lukyth
1068
1123
  [@marcmaniez]: https://github.com/MarcManiez
1069
1124
  [@masqita]: https://github.com/masqita
1070
1125
  [@matt-wratt]: https://github.com/matt-wratt
1071
1126
  [@meleyal]: https://github.com/meleyal
1072
1127
  [@mmainz]: https://github.com/mmainz
1073
1128
  [@mmcnl]: https://github.com/mmcnl
1129
+ [@nathan-beam]: https://github.com/nathan-beam
1074
1130
  [@noahtheduke]: https://github.com/NoahTheDuke
1075
1131
  [@overload119]: https://github.com/Overload119
1076
1132
  [@petevk]: https://github.com/petevk
@@ -22,7 +22,7 @@ In order to get printed, the code goes through a couple of transformations. The
22
22
 
23
23
  ### Text to AST
24
24
 
25
- When the prettier process first spins up, it examines which files it's going to print and selects an appropriate plugin for each one. Once selected, it runs that plugin's `parse` function, seen [here](src/parser.js). For the case of the Ruby plugin, that entails spawning a Ruby process that runs [parser.rb](src/parser.rb) with the input code preloaded on stdin.
25
+ When the prettier process first spins up, it examines which files it's going to print and selects an appropriate plugin for each one. Once selected, it runs that plugin's `parse` function, seen [here](src/ruby/parser.js). For the case of the Ruby plugin, that entails spawning a Ruby process that runs [parser.rb](src/ruby/parser.rb) with the input code preloaded on stdin.
26
26
 
27
27
  `parser.rb` will read the text off of stdin and then feed it to a new `Ripper` instance, which is a Ruby standard library recursive-descent parser. Briefly, the way that `Ripper` works is by tokenizing the input and then matching those tokens against a grammar to form s-expressions. To extend `Ripper`, you overwrite the methods that control how those s-expressions are formed, e.g., to modify the s-expression that is formed when `Ripper` encounters a string literal, you would override the `#on_string_literal` method. Below is an example for seeing that in action.
28
28
 
@@ -71,7 +71,7 @@ Now that the text has been transformed into an AST that we can work with, `parse
71
71
 
72
72
  ### AST to Doc
73
73
 
74
- Once prettier has a working AST, it will take it and call the selected plugin's [`printNode` function](src/printer.js), whose purpose is to convert that AST into prettier's intermediate representation called Docs. It does this by handing the print function a `FastPath` object that keeps track of the state of the printing as it goes, and allows accessing various parts of the AST quickly.
74
+ Once prettier has a working AST, it will take it and call the selected plugin's [`printNode` function](src/ruby/printer.js), whose purpose is to convert that AST into prettier's intermediate representation called Docs. It does this by handing the print function a `FastPath` object that keeps track of the state of the printing as it goes, and allows accessing various parts of the AST quickly.
75
75
 
76
76
  Effectively, it walks the AST in the reverse direction from the way `Ripper` built it (top-down instead of bottom-up). The first node that gets passed into the `print` function is the `program` node as that's always on top. Then it is the `program` node's responsibility to recursively call print on its child nodes as it best sees fit.
77
77
 
data/README.md CHANGED
@@ -120,7 +120,7 @@ The `prettier` executable is now installed and ready for use:
120
120
 
121
121
  ## Configuration
122
122
 
123
- Below are the options (from [`src/ruby.js`](src/ruby.js)) that `@prettier/plugin-ruby` currently supports:
123
+ Below are the options (from [`src/plugin.js`](src/plugin.js)) that `@prettier/plugin-ruby` currently supports:
124
124
 
125
125
  | API Option | CLI Option | Default | Description |
126
126
  | ------------------ | ---------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------------------ |
@@ -149,6 +149,19 @@ Or, they can be passed to `prettier` as arguments:
149
149
  prettier --ruby-single-quote false --write '**/*.rb'
150
150
  ```
151
151
 
152
+ ### Usage with RuboCop
153
+
154
+ RuboCop and Prettier for Ruby serve different purposes, but there is overlap
155
+ with some of RuboCop's functionality.
156
+
157
+ Prettier provides a RuboCop configuration fle to disable the rules which clash.
158
+ To enable, add the following config at the top of your project's `.rubocop.yml`:
159
+
160
+ ```yaml
161
+ inherit_gem:
162
+ prettier: rubocop.yml
163
+ ```
164
+
152
165
  ## Contributing
153
166
 
154
167
  Check out our [contributing guide](CONTRIBUTING.md). Bug reports and pull requests are welcome on GitHub at https://github.com/prettier/plugin-ruby.
@@ -230,6 +243,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
230
243
  <td align="center"><a href="https://github.com/rindek"><img src="https://avatars1.githubusercontent.com/u/881209?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacek Jakubik</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Arindek" title="Bug reports">🐛</a></td>
231
244
  <td align="center"><a href="https://twitter.com/ykpythemind"><img src="https://avatars2.githubusercontent.com/u/22209702?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yukito Ito</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Aykpythemind" title="Bug reports">🐛</a> <a href="https://github.com/prettier/plugin-ruby/commits?author=ykpythemind" title="Code">💻</a></td>
232
245
  <td align="center"><a href="https://studyfied.com/"><img src="https://avatars2.githubusercontent.com/u/45869605?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Karan Mandal</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Akaranmandal" title="Bug reports">🐛</a></td>
246
+ <td align="center"><a href="http://nathanbeam.codes/"><img src="https://avatars3.githubusercontent.com/u/24681333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nathan Beam</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Anathan-beam" title="Bug reports">🐛</a> <a href="https://github.com/prettier/plugin-ruby/commits?author=nathan-beam" title="Code">💻</a></td>
247
+ <td align="center"><a href="https://github.com/blampe"><img src="https://avatars3.githubusercontent.com/u/848843?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bryce Lampe</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Ablampe" title="Bug reports">🐛</a></td>
233
248
  </tr>
234
249
  </table>
235
250
 
@@ -9,8 +9,8 @@ module Prettier
9
9
 
10
10
  class << self
11
11
  def run(args)
12
- quoted = args.map { |arg| arg.start_with?('-') ? arg : "'#{arg}'" }
13
- command = "node #{BINARY} --plugin '#{PLUGIN}' #{quoted.join(' ')}"
12
+ quoted = args.map { |arg| arg.start_with?('-') ? arg : "\"#{arg}\"" }
13
+ command = "node #{BINARY} --plugin \"#{PLUGIN}\" #{quoted.join(' ')}"
14
14
 
15
15
  system({ 'RBPRETTIER' => '1' }, command)
16
16
  end
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@prettier/plugin-ruby",
3
- "version": "1.1.0",
3
+ "version": "1.2.4",
4
4
  "description": "prettier plugin for the Ruby programming language",
5
- "main": "src/ruby.js",
5
+ "main": "src/plugin.js",
6
6
  "scripts": {
7
7
  "check-format": "prettier --check '**/*'",
8
8
  "lint": "eslint --cache .",
@@ -0,0 +1,26 @@
1
+ # Disabling all Layout/* rules, as they're unnecessary when the user is using
2
+ # prettier to handle all of the formatting.
3
+
4
+ Layout:
5
+ Enabled: false
6
+
7
+ # Disabling all of the following options because they could conflict with a
8
+ # prettier configuration setting.
9
+
10
+ Style/MultilineIfModifier: # rubyModifier
11
+ Enabled: false
12
+
13
+ Style/SymbolArray: # rubyArrayLiteral
14
+ Enabled: false
15
+
16
+ Style/WordArray: # rubyArrayLiteral
17
+ Enabled: false
18
+
19
+ Style/TrailingCommaInArguments: # trailingComma
20
+ Enabled: false
21
+
22
+ Style/TrailingCommaInArrayLiteral: # trailingComma
23
+ Enabled: false
24
+
25
+ Style/TrailingCommaInHashLiteral: # trailingComma
26
+ Enabled: false
@@ -1,5 +1,5 @@
1
- const printer = require("./printer");
2
- const parser = require("./parser");
1
+ const printer = require("./ruby/printer");
2
+ const parser = require("./ruby/parser");
3
3
 
4
4
  /*
5
5
  * metadata mostly pulled from linguist and rubocop:
@@ -1,6 +1,7 @@
1
1
  // If `RBPRETTIER` is set, then this is being run from the `Prettier::run` ruby
2
2
  // method. In that case, we need to pull `prettier` from the node_modules
3
3
  // directly, as it's been shipped with the gem.
4
+ /* istanbul ignore next */
4
5
  const source = process.env.RBPRETTIER ? "../node_modules/prettier" : "prettier";
5
6
 
6
7
  const prettier = require(source);
@@ -6,9 +6,9 @@ const {
6
6
  mapDoc,
7
7
  markAsRoot,
8
8
  stripTrailingHardline
9
- } = require("./prettier");
9
+ } = require("../prettier");
10
10
 
11
- const { literalLineNoBreak } = require("./utils");
11
+ const { literalLineNoBreak } = require("../utils");
12
12
 
13
13
  const parsers = {
14
14
  css: "css",
@@ -20,6 +20,10 @@ const parsers = {
20
20
  scss: "scss"
21
21
  };
22
22
 
23
+ // This function is in here because it handles embedded parser values. I don't
24
+ // have a test that exercises it because I'm not sure for which parser it is
25
+ // necessary, but since it's in prettier core I'm keeping it here.
26
+ /* istanbul ignore next */
23
27
  const replaceNewlines = (doc) =>
24
28
  mapDoc(doc, (currentDoc) =>
25
29
  typeof currentDoc === "string" && currentDoc.includes("\n")
File without changes
@@ -5,7 +5,7 @@ const {
5
5
  group,
6
6
  hardline,
7
7
  line
8
- } = require("../prettier");
8
+ } = require("../../prettier");
9
9
 
10
10
  // In general, return the printed doc of the argument at the provided index.
11
11
  // Special handling is given for symbol literals that are not bare words, as we
@@ -1,4 +1,11 @@
1
- const { concat, group, indent, join, line, softline } = require("../prettier");
1
+ const {
2
+ concat,
3
+ group,
4
+ indent,
5
+ join,
6
+ line,
7
+ softline
8
+ } = require("../../prettier");
2
9
 
3
10
  // `aref` nodes are when you're pulling a value out of a collection at a
4
11
  // specific index. Put another way, it's any time you're calling the method
@@ -6,10 +6,10 @@ const {
6
6
  join,
7
7
  line,
8
8
  softline
9
- } = require("../prettier");
9
+ } = require("../../prettier");
10
+ const { getTrailingComma } = require("../../utils");
10
11
 
11
12
  const toProc = require("../toProc");
12
- const { getTrailingComma } = require("../utils");
13
13
 
14
14
  function printArgParen(path, opts, print) {
15
15
  const argsNode = path.getValue().body[0];
@@ -6,9 +6,8 @@ const {
6
6
  join,
7
7
  line,
8
8
  softline
9
- } = require("../prettier");
10
-
11
- const { getTrailingComma, printEmptyCollection } = require("../utils");
9
+ } = require("../../prettier");
10
+ const { getTrailingComma, printEmptyCollection } = require("../../utils");
12
11
 
13
12
  // Checks that every argument within this args node is a string_literal node
14
13
  // that has no spaces or interpolations. This means we're dealing with an array
@@ -1,5 +1,5 @@
1
- const { concat, group, indent, join, line } = require("../prettier");
2
- const { first, skipAssignIndent } = require("../utils");
1
+ const { concat, group, indent, join, line } = require("../../prettier");
2
+ const { skipAssignIndent } = require("../../utils");
3
3
 
4
4
  function printAssign(path, opts, print) {
5
5
  const [_targetNode, valueNode] = path.getValue().body;
@@ -31,9 +31,17 @@ function printOpAssign(path, opts, print) {
31
31
  );
32
32
  }
33
33
 
34
+ function printVarField(path, opts, print) {
35
+ return path.getValue().body ? path.call(print, "body", 0) : "";
36
+ }
37
+
38
+ function printVarRef(path, opts, print) {
39
+ return path.call(print, "body", 0);
40
+ }
41
+
34
42
  module.exports = {
35
43
  assign: printAssign,
36
44
  opassign: printOpAssign,
37
- var_field: first,
38
- var_ref: first
45
+ var_field: printVarField,
46
+ var_ref: printVarRef
39
47
  };
@@ -0,0 +1,90 @@
1
+ const {
2
+ breakParent,
3
+ concat,
4
+ group,
5
+ ifBreak,
6
+ indent,
7
+ join,
8
+ removeLines,
9
+ softline
10
+ } = require("../../prettier");
11
+ const { hasAncestor } = require("../../utils");
12
+
13
+ function printBlockVar(path, opts, print) {
14
+ const parts = ["|", removeLines(path.call(print, "body", 0))];
15
+
16
+ // The second part of this node is a list of optional block-local variables
17
+ if (path.getValue().body[1]) {
18
+ parts.push("; ", join(", ", path.map(print, "body", 1)));
19
+ }
20
+
21
+ parts.push("| ");
22
+ return concat(parts);
23
+ }
24
+
25
+ function printBlock(braces) {
26
+ return function printBlockWithBraces(path, opts, print) {
27
+ const [variables, statements] = path.getValue().body;
28
+ const stmts =
29
+ statements.type === "stmts" ? statements.body : statements.body[0].body;
30
+
31
+ let doBlockBody = "";
32
+ if (
33
+ stmts.length !== 1 ||
34
+ stmts[0].type !== "void_stmt" ||
35
+ stmts[0].comments
36
+ ) {
37
+ doBlockBody = indent(concat([softline, path.call(print, "body", 1)]));
38
+ }
39
+
40
+ // If this block is nested underneath a command or command_call node, then
41
+ // we can't use `do...end` because that will get associated with the parent
42
+ // node as opposed to the current node (because of the difference in
43
+ // operator precedence). Instead, we still use a multi-line format but
44
+ // switch to using braces instead.
45
+ const useBraces = braces && hasAncestor(path, ["command", "command_call"]);
46
+
47
+ const doBlock = concat([
48
+ useBraces ? " {" : " do",
49
+ variables ? concat([" ", path.call(print, "body", 0)]) : "",
50
+ doBlockBody,
51
+ concat([softline, useBraces ? "}" : "end"])
52
+ ]);
53
+
54
+ // We can hit this next pattern if within the block the only statement is a
55
+ // comment.
56
+ if (
57
+ stmts.length === 1 &&
58
+ stmts[0].type === "void_stmt" &&
59
+ stmts[0].comments
60
+ ) {
61
+ return concat([breakParent, doBlock]);
62
+ }
63
+
64
+ const blockReceiver = path.getParentNode().body[0];
65
+
66
+ // If the parent node is a command node, then there are no parentheses
67
+ // around the arguments to that command, so we need to break the block
68
+ if (["command", "command_call"].includes(blockReceiver.type)) {
69
+ return concat([breakParent, doBlock]);
70
+ }
71
+
72
+ const hasBody = stmts.some(({ type }) => type !== "void_stmt");
73
+ const braceBlock = concat([
74
+ " {",
75
+ hasBody || variables ? " " : "",
76
+ variables ? path.call(print, "body", 0) : "",
77
+ path.call(print, "body", 1),
78
+ hasBody ? " " : "",
79
+ "}"
80
+ ]);
81
+
82
+ return group(ifBreak(doBlock, braceBlock));
83
+ };
84
+ }
85
+
86
+ module.exports = {
87
+ block_var: printBlockVar,
88
+ brace_block: printBlock(true),
89
+ do_block: printBlock(false)
90
+ };
@@ -5,8 +5,8 @@ const {
5
5
  ifBreak,
6
6
  indent,
7
7
  softline
8
- } = require("../prettier");
9
- const { first, makeCall, noIndent } = require("../utils");
8
+ } = require("../../prettier");
9
+ const { makeCall, noIndent } = require("../../utils");
10
10
 
11
11
  const toProc = require("../toProc");
12
12
 
@@ -41,15 +41,18 @@ function printCall(path, opts, print) {
41
41
  parentNode.chain = (node.chain || 0) + 1;
42
42
  parentNode.callChain = (node.callChain || 0) + 1;
43
43
  parentNode.breakDoc = (node.breakDoc || [receiverDoc]).concat(rightSideDoc);
44
+ parentNode.firstReceiverType = node.firstReceiverType || receiverNode.type;
44
45
  }
45
46
 
46
47
  // If we're at the top of a chain, then we're going to print out a nice
47
48
  // multi-line layout if this doesn't break into multiple lines.
48
49
  if (!chained.includes(parentNode.type) && (node.chain || 0) >= 3) {
49
- return ifBreak(
50
- group(indent(concat(node.breakDoc.concat(rightSideDoc)))),
51
- concat([receiverDoc, group(rightSideDoc)])
52
- );
50
+ let breakDoc = concat(node.breakDoc.concat(rightSideDoc));
51
+ if (!noIndent.includes(node.firstReceiverType)) {
52
+ breakDoc = indent(breakDoc);
53
+ }
54
+
55
+ return ifBreak(group(breakDoc), concat([receiverDoc, group(rightSideDoc)]));
53
56
  }
54
57
 
55
58
  // For certain left sides of the call nodes, we want to attach directly to
@@ -105,6 +108,7 @@ function printMethodAddArg(path, opts, print) {
105
108
  if (chained.includes(parentNode.type)) {
106
109
  parentNode.chain = (node.chain || 0) + 1;
107
110
  parentNode.breakDoc = (node.breakDoc || [methodDoc]).concat(argsDoc);
111
+ parentNode.firstReceiverType = node.firstReceiverType;
108
112
  }
109
113
 
110
114
  // If we're at the top of a chain, then we're going to print out a nice
@@ -152,7 +156,7 @@ function isSorbetTypeAnnotation(node) {
152
156
  callNode.body[0].body[0].body === "sig" &&
153
157
  callNode.body[1].type === "args" &&
154
158
  callNode.body[1].body.length === 0 &&
155
- blockNode.type === "brace_block"
159
+ blockNode
156
160
  );
157
161
  }
158
162
 
@@ -198,6 +202,7 @@ function printMethodAddBlock(path, opts, print) {
198
202
  if (chained.includes(parentNode.type)) {
199
203
  parentNode.chain = (node.chain || 0) + 1;
200
204
  parentNode.breakDoc = (node.breakDoc || [callDoc]).concat(blockDoc);
205
+ parentNode.firstReceiverType = node.firstReceiverType;
201
206
  }
202
207
 
203
208
  // If we're at the top of a chain, then we're going to print out a nice
@@ -212,10 +217,14 @@ function printMethodAddBlock(path, opts, print) {
212
217
  return concat([callDoc, blockDoc]);
213
218
  }
214
219
 
220
+ function printCallContainer(path, opts, print) {
221
+ return path.call(print, "body", 0);
222
+ }
223
+
215
224
  module.exports = {
216
225
  call: printCall,
217
- fcall: first,
226
+ fcall: printCallContainer,
218
227
  method_add_arg: printMethodAddArg,
219
228
  method_add_block: printMethodAddBlock,
220
- vcall: first
229
+ vcall: printCallContainer
221
230
  };