prettier 0.15.0 → 0.15.1
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.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +68 -1
 - data/CONTRIBUTING.md +12 -0
 - data/README.md +2 -0
 - data/package.json +2 -2
 - data/src/nodes/conditionals.js +54 -13
 - data/src/nodes/hashes.js +16 -5
 - data/src/nodes/loops.js +32 -4
 - data/src/nodes/strings.js +15 -25
 - data/src/ripper.rb +4 -3
 - data/src/utils.js +7 -0
 - metadata +3 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b3562a5d108cf70183f77a181bc6d2370c28119596741bfedaf0f40b17062098
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: ecafaf2f71979173250bf03aabe13c7d6fa5d6fe4f7373042405c81bdc6a3b60
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: fc85edcee8ac7892a6d3b0e727abff488d72a5ecfa717383229774f24faae4bf0384f77e1c5c459586b363dc8822968413c1e0aa8da8f998ca46ccf986a3344b
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 79f754fd9fa9a46171e9c8a6871d4b487fd4cc19a8cb21527b5a0d322761771d3339e28bdc4128ab044240d5a7c149a9ea6c40d8acb1db036ecdea7163419af0
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -6,6 +6,72 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            ## [Unreleased]
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
      
 9 
     | 
    
         
            +
            ## [0.15.1] - 2019-11-05
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            ### Changed
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            - [INTERNAL] Add `bin/lex` for viewing the tokenized result of Ripper on Ruby code (Thanks to @AlanFoster.)
         
     | 
| 
      
 14 
     | 
    
         
            +
            - When predicates from within an `if`, `unless`, `while`, or `until` loop break the line, they should be aligned together. For example,
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            <!-- prettier-ignore -->
         
     | 
| 
      
 17 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 18 
     | 
    
         
            +
            if foooooo || barrrrrr
         
     | 
| 
      
 19 
     | 
    
         
            +
              baz
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
      
 21 
     | 
    
         
            +
            ```
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            If the line was set to very short, the binary node should be aligned to 3 spaces from the left of the file (which aligns with the `if`, it would be more for `unless`). So it would look like:
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            <!-- prettier-ignore -->
         
     | 
| 
      
 26 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 27 
     | 
    
         
            +
            if foooooo ||
         
     | 
| 
      
 28 
     | 
    
         
            +
                 barrrrrr
         
     | 
| 
      
 29 
     | 
    
         
            +
              baz
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
            ```
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            (Thanks to @jakeprime for the report.)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            - Empty `if`, and `unless` conditionals are now handled gracefully:
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            <!-- prettier-ignore -->
         
     | 
| 
      
 38 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 39 
     | 
    
         
            +
            if foo?
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
            ```
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            (Thanks to @AlanFoster for the fix, and @jamescostian for the report.)
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            - Hash keys are not converted to keyword syntax if they would make invalid symbols. For example,
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            <!-- prettier-ignore -->
         
     | 
| 
      
 48 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 49 
     | 
    
         
            +
            { :[] => nil }
         
     | 
| 
      
 50 
     | 
    
         
            +
            ```
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            cannot be translated into `[]:` as that is an invalid symbol. Instead, it stays with the hash rocket syntax. (Thanks to @mmainz for the report.)
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            - Do not attempt to format the insides of xstring literals (string that get sent to the command line surrounded by backticks or `%x`). (Thanks to @cldevs for the report.)
         
     | 
| 
      
 55 
     | 
    
         
            +
            - When predicates for `if`, `unless`, `while`, or `until` nodes contain an assignment, we can't know for sure that it doesn't modify the body. In this case we need to always break and form a multi-line block. (Thanks to @cldevs for the report.)
         
     | 
| 
      
 56 
     | 
    
         
            +
            - When the return value of `if`, `unless`, `while`, or `until` nodes are assigned to anything other than a local variable, we need to wrap them in parentheses if we're changing to the modifier form. This is because the following expressions have different semantic meaning:
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            <!-- prettier-ignore -->
         
     | 
| 
      
 59 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 60 
     | 
    
         
            +
            hash[:key] = break :value while false
         
     | 
| 
      
 61 
     | 
    
         
            +
            hash[:key] = while false do break :value end
         
     | 
| 
      
 62 
     | 
    
         
            +
            ```
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            The first one will not result in an empty hash, whereas the second one will result in `{ key: nil }`. In this case what we need to do for the first expression to align is wrap it in parens, as in:
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            <!-- prettier-ignore -->
         
     | 
| 
      
 67 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 68 
     | 
    
         
            +
            hash[:key] = (break :value while false)
         
     | 
| 
      
 69 
     | 
    
         
            +
            ```
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            That will guarantee that the expressions are equivalent. (Thanks to @MarcManiez for the report.)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            - Fix crashes that were happening with `ignored_nl` nodes. (Thanks to @AlanFoster.)
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
       9 
75 
     | 
    
         
             
            ## [0.15.0] - 2019-08-06
         
     | 
| 
       10 
76 
     | 
    
         | 
| 
       11 
77 
     | 
    
         
             
            ### Changed
         
     | 
| 
         @@ -545,7 +611,8 @@ would previously result in `array[]`, but now prints properly. (Thanks to @xipgr 
     | 
|
| 
       545 
611 
     | 
    
         | 
| 
       546 
612 
     | 
    
         
             
            - Initial release 🎉
         
     | 
| 
       547 
613 
     | 
    
         | 
| 
       548 
     | 
    
         
            -
            [unreleased]: https://github.com/prettier/plugin-ruby/compare/v0.15. 
     | 
| 
      
 614 
     | 
    
         
            +
            [unreleased]: https://github.com/prettier/plugin-ruby/compare/v0.15.1...HEAD
         
     | 
| 
      
 615 
     | 
    
         
            +
            [0.15.1]: https://github.com/prettier/plugin-ruby/compare/v0.15.0...v0.15.1
         
     | 
| 
       549 
616 
     | 
    
         
             
            [0.15.0]: https://github.com/prettier/plugin-ruby/compare/v0.14.0...v0.15.0
         
     | 
| 
       550 
617 
     | 
    
         
             
            [0.14.0]: https://github.com/prettier/plugin-ruby/compare/v0.13.0...v0.14.0
         
     | 
| 
       551 
618 
     | 
    
         
             
            [0.13.0]: https://github.com/prettier/plugin-ruby/compare/v0.12.3...v0.13.0
         
     | 
    
        data/CONTRIBUTING.md
    CHANGED
    
    | 
         @@ -118,6 +118,18 @@ yarn run test 
     | 
|
| 
       118 
118 
     | 
    
         
             
            yarn run test -u
         
     | 
| 
       119 
119 
     | 
    
         
             
            ```
         
     | 
| 
       120 
120 
     | 
    
         | 
| 
      
 121 
     | 
    
         
            +
            **Viewing the tokenized result of Ripper on code**
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            ```
         
     | 
| 
      
 124 
     | 
    
         
            +
            bin/lex 'your_ruby_code(1, 2, 3)'
         
     | 
| 
      
 125 
     | 
    
         
            +
            ```
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
            **Viewing the tokenized result of Ripper on a file**
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            ```
         
     | 
| 
      
 130 
     | 
    
         
            +
            bin/lex file.rb
         
     | 
| 
      
 131 
     | 
    
         
            +
            ```
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
       121 
133 
     | 
    
         
             
            **Viewing the output of RipperJS on a file**
         
     | 
| 
       122 
134 
     | 
    
         | 
| 
       123 
135 
     | 
    
         
             
            ```
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -191,6 +191,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d 
     | 
|
| 
       191 
191 
     | 
    
         
             
              </tr>
         
     | 
| 
       192 
192 
     | 
    
         
             
              <tr>
         
     | 
| 
       193 
193 
     | 
    
         
             
                <td align="center"><a href="https://github.com/jakeprime"><img src="https://avatars1.githubusercontent.com/u/1019036?v=4" width="100px;" alt="jakeprime"/><br /><sub><b>jakeprime</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Ajakeprime" title="Bug reports">🐛</a></td>
         
     | 
| 
      
 194 
     | 
    
         
            +
                <td align="center"><a href="http://mmainz.github.io"><img src="https://avatars2.githubusercontent.com/u/5417714?v=4" width="100px;" alt="Mario Mainz"/><br /><sub><b>Mario Mainz</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Ammainz" title="Bug reports">🐛</a></td>
         
     | 
| 
      
 195 
     | 
    
         
            +
                <td align="center"><a href="http://www.cldevs.com"><img src="https://avatars3.githubusercontent.com/u/38632061?v=4" width="100px;" alt="CL Web Developers"/><br /><sub><b>CL Web Developers</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Acldevs" title="Bug reports">🐛</a></td>
         
     | 
| 
       194 
196 
     | 
    
         
             
              </tr>
         
     | 
| 
       195 
197 
     | 
    
         
             
            </table>
         
     | 
| 
       196 
198 
     | 
    
         | 
    
        data/package.json
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            {
         
     | 
| 
       2 
2 
     | 
    
         
             
              "name": "@prettier/plugin-ruby",
         
     | 
| 
       3 
     | 
    
         
            -
              "version": "0.15. 
     | 
| 
      
 3 
     | 
    
         
            +
              "version": "0.15.1",
         
     | 
| 
       4 
4 
     | 
    
         
             
              "description": "prettier plugin for the Ruby programming language",
         
     | 
| 
       5 
5 
     | 
    
         
             
              "main": "src/ruby.js",
         
     | 
| 
       6 
6 
     | 
    
         
             
              "scripts": {
         
     | 
| 
         @@ -24,7 +24,7 @@ 
     | 
|
| 
       24 
24 
     | 
    
         
             
              "devDependencies": {
         
     | 
| 
       25 
25 
     | 
    
         
             
                "all-contributors-cli": "^6.1.2",
         
     | 
| 
       26 
26 
     | 
    
         
             
                "eslint": "^6.0.1",
         
     | 
| 
       27 
     | 
    
         
            -
                "eslint-config-airbnb-base": "^ 
     | 
| 
      
 27 
     | 
    
         
            +
                "eslint-config-airbnb-base": "^14.0.0",
         
     | 
| 
       28 
28 
     | 
    
         
             
                "eslint-config-prettier": "^6.0.0",
         
     | 
| 
       29 
29 
     | 
    
         
             
                "eslint-plugin-import": "^2.16.0",
         
     | 
| 
       30 
30 
     | 
    
         
             
                "jest": "^24.0.0"
         
     | 
    
        data/src/nodes/conditionals.js
    CHANGED
    
    | 
         @@ -8,6 +8,7 @@ const { 
     | 
|
| 
       8 
8 
     | 
    
         
             
              indent,
         
     | 
| 
       9 
9 
     | 
    
         
             
              softline
         
     | 
| 
       10 
10 
     | 
    
         
             
            } = require("../prettier");
         
     | 
| 
      
 11 
     | 
    
         
            +
            const { containsAssignment } = require("../utils");
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
13 
     | 
    
         
             
            const noTernary = [
         
     | 
| 
       13 
14 
     | 
    
         
             
              "@comment",
         
     | 
| 
         @@ -40,7 +41,7 @@ const noTernary = [ 
     | 
|
| 
       40 
41 
     | 
    
         
             
            const printWithAddition = (keyword, path, print, { breaking = false } = {}) =>
         
     | 
| 
       41 
42 
     | 
    
         
             
              concat([
         
     | 
| 
       42 
43 
     | 
    
         
             
                `${keyword} `,
         
     | 
| 
       43 
     | 
    
         
            -
                align(keyword.length  
     | 
| 
      
 44 
     | 
    
         
            +
                align(keyword.length + 1, path.call(print, "body", 0)),
         
     | 
| 
       44 
45 
     | 
    
         
             
                indent(concat([softline, path.call(print, "body", 1)])),
         
     | 
| 
       45 
46 
     | 
    
         
             
                concat([softline, path.call(print, "body", 2)]),
         
     | 
| 
       46 
47 
     | 
    
         
             
                concat([softline, "end"]),
         
     | 
| 
         @@ -91,7 +92,7 @@ const printTernary = (path, _opts, print) => { 
     | 
|
| 
       91 
92 
     | 
    
         
             
                ifBreak(
         
     | 
| 
       92 
93 
     | 
    
         
             
                  concat([
         
     | 
| 
       93 
94 
     | 
    
         
             
                    "if ",
         
     | 
| 
       94 
     | 
    
         
            -
                    predicate,
         
     | 
| 
      
 95 
     | 
    
         
            +
                    align(3, predicate),
         
     | 
| 
       95 
96 
     | 
    
         
             
                    indent(concat([softline, truthyClause])),
         
     | 
| 
       96 
97 
     | 
    
         
             
                    concat([softline, "else"]),
         
     | 
| 
       97 
98 
     | 
    
         
             
                    indent(concat([softline, falsyClause])),
         
     | 
| 
         @@ -102,31 +103,52 @@ const printTernary = (path, _opts, print) => { 
     | 
|
| 
       102 
103 
     | 
    
         
             
              );
         
     | 
| 
       103 
104 
     | 
    
         
             
            };
         
     | 
| 
       104 
105 
     | 
    
         | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
            // just work with the predicate and the body.
         
     | 
| 
       108 
     | 
    
         
            -
            const printSingle = keyword => (path, { inlineConditionals }, print) => {
         
     | 
| 
       109 
     | 
    
         
            -
              const multiline = concat([
         
     | 
| 
      
 106 
     | 
    
         
            +
            const makeSingleBlockForm = (keyword, path, print) =>
         
     | 
| 
      
 107 
     | 
    
         
            +
              concat([
         
     | 
| 
       110 
108 
     | 
    
         
             
                `${keyword} `,
         
     | 
| 
       111 
     | 
    
         
            -
                align(keyword.length  
     | 
| 
      
 109 
     | 
    
         
            +
                align(keyword.length + 1, path.call(print, "body", 0)),
         
     | 
| 
       112 
110 
     | 
    
         
             
                indent(concat([softline, path.call(print, "body", 1)])),
         
     | 
| 
       113 
111 
     | 
    
         
             
                concat([softline, "end"])
         
     | 
| 
       114 
112 
     | 
    
         
             
              ]);
         
     | 
| 
       115 
113 
     | 
    
         | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
      
 114 
     | 
    
         
            +
            // Prints an `if_mod` or `unless_mod` node. Because it was previously in the
         
     | 
| 
      
 115 
     | 
    
         
            +
            // modifier form, we're guaranteed to not have an additional node, so we can
         
     | 
| 
      
 116 
     | 
    
         
            +
            // just work with the predicate and the body.
         
     | 
| 
      
 117 
     | 
    
         
            +
            const printSingle = keyword => (path, { inlineConditionals }, print) => {
         
     | 
| 
      
 118 
     | 
    
         
            +
              const multiline = makeSingleBlockForm(keyword, path, print);
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
              const [_predicate, stmts] = path.getValue().body;
         
     | 
| 
       117 
121 
     | 
    
         
             
              const hasComments =
         
     | 
| 
       118 
122 
     | 
    
         
             
                stmts.type === "stmts" && stmts.body.some(stmt => stmt.type === "@comment");
         
     | 
| 
       119 
123 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
              if (!inlineConditionals || hasComments 
     | 
| 
      
 124 
     | 
    
         
            +
              if (!inlineConditionals || hasComments) {
         
     | 
| 
       121 
125 
     | 
    
         
             
                return multiline;
         
     | 
| 
       122 
126 
     | 
    
         
             
              }
         
     | 
| 
       123 
127 
     | 
    
         | 
| 
       124 
     | 
    
         
            -
               
     | 
| 
      
 128 
     | 
    
         
            +
              let inlineParts = [
         
     | 
| 
       125 
129 
     | 
    
         
             
                path.call(print, "body", 1),
         
     | 
| 
       126 
130 
     | 
    
         
             
                ` ${keyword} `,
         
     | 
| 
       127 
131 
     | 
    
         
             
                path.call(print, "body", 0)
         
     | 
| 
       128 
     | 
    
         
            -
              ] 
     | 
| 
      
 132 
     | 
    
         
            +
              ];
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
              // If the return value of this conditional expression is being assigned to
         
     | 
| 
      
 135 
     | 
    
         
            +
              // anything besides a local variable then we can't inline the entire
         
     | 
| 
      
 136 
     | 
    
         
            +
              // expression without wrapping it in parentheses. This is because the
         
     | 
| 
      
 137 
     | 
    
         
            +
              // following expressions have different semantic meaning:
         
     | 
| 
      
 138 
     | 
    
         
            +
              //
         
     | 
| 
      
 139 
     | 
    
         
            +
              //     hash[:key] = :value if false
         
     | 
| 
      
 140 
     | 
    
         
            +
              //     hash[:key] = if false then :value end
         
     | 
| 
      
 141 
     | 
    
         
            +
              //
         
     | 
| 
      
 142 
     | 
    
         
            +
              // The first one will not result in an empty hash, whereas the second one
         
     | 
| 
      
 143 
     | 
    
         
            +
              // will result in `{ key: nil }`. In this case what we need to do for the
         
     | 
| 
      
 144 
     | 
    
         
            +
              // first expression to align is wrap it in parens, as in:
         
     | 
| 
      
 145 
     | 
    
         
            +
              //
         
     | 
| 
      
 146 
     | 
    
         
            +
              //     hash[:key] = (:value if false)
         
     | 
| 
      
 147 
     | 
    
         
            +
              if (["assign", "massign"].includes(path.getParentNode().type)) {
         
     | 
| 
      
 148 
     | 
    
         
            +
                inlineParts = ["("].concat(inlineParts).concat(")");
         
     | 
| 
      
 149 
     | 
    
         
            +
              }
         
     | 
| 
       129 
150 
     | 
    
         | 
| 
      
 151 
     | 
    
         
            +
              const inline = concat(inlineParts);
         
     | 
| 
       130 
152 
     | 
    
         
             
              return group(ifBreak(multiline, inline));
         
     | 
| 
       131 
153 
     | 
    
         
             
            };
         
     | 
| 
       132 
154 
     | 
    
         | 
| 
         @@ -171,12 +193,31 @@ const printConditional = keyword => (path, { inlineConditionals }, print) => { 
     | 
|
| 
       171 
193 
     | 
    
         
             
                );
         
     | 
| 
       172 
194 
     | 
    
         
             
              }
         
     | 
| 
       173 
195 
     | 
    
         | 
| 
      
 196 
     | 
    
         
            +
              const [predicate, statements, addition] = path.getValue().body;
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
       174 
198 
     | 
    
         
             
              // If there's an additional clause that wasn't matched earlier, we know we
         
     | 
| 
       175 
199 
     | 
    
         
             
              // can't go for the inline option.
         
     | 
| 
       176 
     | 
    
         
            -
              if ( 
     | 
| 
      
 200 
     | 
    
         
            +
              if (addition) {
         
     | 
| 
       177 
201 
     | 
    
         
             
                return group(printWithAddition(keyword, path, print, { breaking: true }));
         
     | 
| 
       178 
202 
     | 
    
         
             
              }
         
     | 
| 
       179 
203 
     | 
    
         | 
| 
      
 204 
     | 
    
         
            +
              // If the body of the conditional is empty, then we explicitly have to use the
         
     | 
| 
      
 205 
     | 
    
         
            +
              // block form.
         
     | 
| 
      
 206 
     | 
    
         
            +
              if (statements.type === "stmts" && statements.body[0].type === "void_stmt") {
         
     | 
| 
      
 207 
     | 
    
         
            +
                return concat([
         
     | 
| 
      
 208 
     | 
    
         
            +
                  `${keyword} `,
         
     | 
| 
      
 209 
     | 
    
         
            +
                  align(keyword.length + 1, path.call(print, "body", 0)),
         
     | 
| 
      
 210 
     | 
    
         
            +
                  concat([hardline, "end"])
         
     | 
| 
      
 211 
     | 
    
         
            +
                ]);
         
     | 
| 
      
 212 
     | 
    
         
            +
              }
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
              // If the predicate of the conditional contains an assignment, then we can't
         
     | 
| 
      
 215 
     | 
    
         
            +
              // know for sure that it doesn't impact the body of the conditional, so we
         
     | 
| 
      
 216 
     | 
    
         
            +
              // have to default to the block form.
         
     | 
| 
      
 217 
     | 
    
         
            +
              if (containsAssignment(predicate)) {
         
     | 
| 
      
 218 
     | 
    
         
            +
                return makeSingleBlockForm(keyword, path, print);
         
     | 
| 
      
 219 
     | 
    
         
            +
              }
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
       180 
221 
     | 
    
         
             
              return printSingle(keyword)(path, { inlineConditionals }, print);
         
     | 
| 
       181 
222 
     | 
    
         
             
            };
         
     | 
| 
       182 
223 
     | 
    
         | 
    
        data/src/nodes/hashes.js
    CHANGED
    
    | 
         @@ -19,6 +19,21 @@ const nodeDive = (node, steps) => { 
     | 
|
| 
       19 
19 
     | 
    
         
             
              return current;
         
     | 
| 
       20 
20 
     | 
    
         
             
            };
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
      
 22 
     | 
    
         
            +
            // When attempting to convert a hash rocket into a hash label, you need to take
         
     | 
| 
      
 23 
     | 
    
         
            +
            // care because only certain patterns are allowed. Ruby source says that they
         
     | 
| 
      
 24 
     | 
    
         
            +
            // have to match keyword arguments to methods, but don't specify what that is.
         
     | 
| 
      
 25 
     | 
    
         
            +
            // After some experimentation, it looks like it's:
         
     | 
| 
      
 26 
     | 
    
         
            +
            //
         
     | 
| 
      
 27 
     | 
    
         
            +
            // * Starts with a letter (either case) or an underscore
         
     | 
| 
      
 28 
     | 
    
         
            +
            // * Does not end in equal
         
     | 
| 
      
 29 
     | 
    
         
            +
            //
         
     | 
| 
      
 30 
     | 
    
         
            +
            // This function represents that check, as it determines if it can convert the
         
     | 
| 
      
 31 
     | 
    
         
            +
            // symbol node into a hash label.
         
     | 
| 
      
 32 
     | 
    
         
            +
            const isValidHashLabel = symbolLiteral => {
         
     | 
| 
      
 33 
     | 
    
         
            +
              const label = symbolLiteral.body[0].body[0].body;
         
     | 
| 
      
 34 
     | 
    
         
            +
              return label.match(/^[_A-Za-z]/) && !label.endsWith("=");
         
     | 
| 
      
 35 
     | 
    
         
            +
            };
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       22 
37 
     | 
    
         
             
            const makeLabel = (path, { preferHashLabels }, print, steps) => {
         
     | 
| 
       23 
38 
     | 
    
         
             
              const labelNode = nodeDive(path.getValue(), steps);
         
     | 
| 
       24 
39 
     | 
    
         
             
              const labelDoc = path.call.apply(path, [print].concat(steps));
         
     | 
| 
         @@ -30,11 +45,7 @@ const makeLabel = (path, { preferHashLabels }, print, steps) => { 
     | 
|
| 
       30 
45 
     | 
    
         
             
                  }
         
     | 
| 
       31 
46 
     | 
    
         
             
                  return `:${labelDoc.slice(0, labelDoc.length - 1)} =>`;
         
     | 
| 
       32 
47 
     | 
    
         
             
                case "symbol_literal": {
         
     | 
| 
       33 
     | 
    
         
            -
                   
     | 
| 
       34 
     | 
    
         
            -
                  // character, which breaks when you use hash labels.
         
     | 
| 
       35 
     | 
    
         
            -
                  const endsInEquals = labelNode.body[0].body[0].body.endsWith("=");
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                  if (preferHashLabels && labelNode.body.length === 1 && !endsInEquals) {
         
     | 
| 
      
 48 
     | 
    
         
            +
                  if (preferHashLabels && isValidHashLabel(labelNode)) {
         
     | 
| 
       38 
49 
     | 
    
         
             
                    const symbolSteps = steps.concat("body", 0, "body", 0);
         
     | 
| 
       39 
50 
     | 
    
         | 
| 
       40 
51 
     | 
    
         
             
                    return concat([
         
     | 
    
        data/src/nodes/loops.js
    CHANGED
    
    | 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            const {
         
     | 
| 
      
 2 
     | 
    
         
            +
              align,
         
     | 
| 
       2 
3 
     | 
    
         
             
              concat,
         
     | 
| 
       3 
4 
     | 
    
         
             
              group,
         
     | 
| 
       4 
5 
     | 
    
         
             
              hardline,
         
     | 
| 
         @@ -6,13 +7,33 @@ const { 
     | 
|
| 
       6 
7 
     | 
    
         
             
              indent,
         
     | 
| 
       7 
8 
     | 
    
         
             
              softline
         
     | 
| 
       8 
9 
     | 
    
         
             
            } = require("../prettier");
         
     | 
| 
      
 10 
     | 
    
         
            +
            const { containsAssignment } = require("../utils");
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
12 
     | 
    
         
             
            const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
         
     | 
| 
       11 
     | 
    
         
            -
               
     | 
| 
      
 13 
     | 
    
         
            +
              let inlineParts = [
         
     | 
| 
       12 
14 
     | 
    
         
             
                path.call(print, "body", 1),
         
     | 
| 
       13 
15 
     | 
    
         
             
                ` ${keyword} `,
         
     | 
| 
       14 
16 
     | 
    
         
             
                path.call(print, "body", 0)
         
     | 
| 
       15 
     | 
    
         
            -
              ] 
     | 
| 
      
 17 
     | 
    
         
            +
              ];
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              // If the return value of this loop expression is being assigned to anything
         
     | 
| 
      
 20 
     | 
    
         
            +
              // besides a local variable then we can't inline the entire expression
         
     | 
| 
      
 21 
     | 
    
         
            +
              // without wrapping it in parentheses. This is because the following
         
     | 
| 
      
 22 
     | 
    
         
            +
              // expressions have different semantic meaning:
         
     | 
| 
      
 23 
     | 
    
         
            +
              //
         
     | 
| 
      
 24 
     | 
    
         
            +
              //     hash[:key] = break :value while false
         
     | 
| 
      
 25 
     | 
    
         
            +
              //     hash[:key] = while false do break :value end
         
     | 
| 
      
 26 
     | 
    
         
            +
              //
         
     | 
| 
      
 27 
     | 
    
         
            +
              // The first one will not result in an empty hash, whereas the second one
         
     | 
| 
      
 28 
     | 
    
         
            +
              // will result in `{ key: nil }`. In this case what we need to do for the
         
     | 
| 
      
 29 
     | 
    
         
            +
              // first expression to align is wrap it in parens, as in:
         
     | 
| 
      
 30 
     | 
    
         
            +
              //
         
     | 
| 
      
 31 
     | 
    
         
            +
              //     hash[:key] = (break :value while false)
         
     | 
| 
      
 32 
     | 
    
         
            +
              if (["assign", "massign"].includes(path.getParentNode().type)) {
         
     | 
| 
      
 33 
     | 
    
         
            +
                inlineParts = ["("].concat(inlineParts).concat(")");
         
     | 
| 
      
 34 
     | 
    
         
            +
              }
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              const inlineLoop = concat(inlineParts);
         
     | 
| 
       16 
37 
     | 
    
         | 
| 
       17 
38 
     | 
    
         
             
              // If we're in the modifier form and we're modifying a `begin`, then this is a
         
     | 
| 
       18 
39 
     | 
    
         
             
              // special case where we need to explicitly use the modifier form because
         
     | 
| 
         @@ -28,12 +49,19 @@ const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => { 
     | 
|
| 
       28 
49 
     | 
    
         
             
              }
         
     | 
| 
       29 
50 
     | 
    
         | 
| 
       30 
51 
     | 
    
         
             
              const blockLoop = concat([
         
     | 
| 
       31 
     | 
    
         
            -
                concat([ 
     | 
| 
      
 52 
     | 
    
         
            +
                concat([
         
     | 
| 
      
 53 
     | 
    
         
            +
                  `${keyword} `,
         
     | 
| 
      
 54 
     | 
    
         
            +
                  align(keyword.length + 1, path.call(print, "body", 0))
         
     | 
| 
      
 55 
     | 
    
         
            +
                ]),
         
     | 
| 
       32 
56 
     | 
    
         
             
                indent(concat([softline, path.call(print, "body", 1)])),
         
     | 
| 
       33 
57 
     | 
    
         
             
                concat([softline, "end"])
         
     | 
| 
       34 
58 
     | 
    
         
             
              ]);
         
     | 
| 
       35 
59 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
              if  
     | 
| 
      
 60 
     | 
    
         
            +
              // If we're disallowing inline loops or if the predicate of the loop contains
         
     | 
| 
      
 61 
     | 
    
         
            +
              // an assignment (in which case we can't know for certain that that
         
     | 
| 
      
 62 
     | 
    
         
            +
              // assignment doesn't impact the statements inside the loop) then we can't
         
     | 
| 
      
 63 
     | 
    
         
            +
              // use the modifier form and we must use the block form.
         
     | 
| 
      
 64 
     | 
    
         
            +
              if (!inlineLoops || containsAssignment(path.getValue().body[0])) {
         
     | 
| 
       37 
65 
     | 
    
         
             
                return blockLoop;
         
     | 
| 
       38 
66 
     | 
    
         
             
              }
         
     | 
| 
       39 
67 
     | 
    
         | 
    
        data/src/nodes/strings.js
    CHANGED
    
    | 
         @@ -3,7 +3,6 @@ const { 
     | 
|
| 
       3 
3 
     | 
    
         
             
              group,
         
     | 
| 
       4 
4 
     | 
    
         
             
              hardline,
         
     | 
| 
       5 
5 
     | 
    
         
             
              indent,
         
     | 
| 
       6 
     | 
    
         
            -
              join,
         
     | 
| 
       7 
6 
     | 
    
         
             
              literalline,
         
     | 
| 
       8 
7 
     | 
    
         
             
              softline
         
     | 
| 
       9 
8 
     | 
    
         
             
            } = require("../prettier");
         
     | 
| 
         @@ -96,14 +95,20 @@ module.exports = { 
     | 
|
| 
       96 
95 
     | 
    
         
             
                  ])
         
     | 
| 
       97 
96 
     | 
    
         
             
                ),
         
     | 
| 
       98 
97 
     | 
    
         
             
              string_dvar: surround("#{", "}"),
         
     | 
| 
       99 
     | 
    
         
            -
              string_embexpr: (path, opts, print) =>
         
     | 
| 
       100 
     | 
    
         
            -
                 
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
      
 98 
     | 
    
         
            +
              string_embexpr: (path, opts, print) => {
         
     | 
| 
      
 99 
     | 
    
         
            +
                const parts = path.call(print, "body", 0);
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                // If the interpolated expression is inside of an xstring literal (a string
         
     | 
| 
      
 102 
     | 
    
         
            +
                // that gets sent to the command line) then we don't want to automatically
         
     | 
| 
      
 103 
     | 
    
         
            +
                // indent, as this can lead to some very odd looking expressions
         
     | 
| 
      
 104 
     | 
    
         
            +
                if (path.getParentNode().type === "xstring") {
         
     | 
| 
      
 105 
     | 
    
         
            +
                  return concat(["#{", parts, "}"]);
         
     | 
| 
      
 106 
     | 
    
         
            +
                }
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                return group(
         
     | 
| 
      
 109 
     | 
    
         
            +
                  concat(["#{", indent(concat([softline, parts])), concat([softline, "}"])])
         
     | 
| 
      
 110 
     | 
    
         
            +
                );
         
     | 
| 
      
 111 
     | 
    
         
            +
              },
         
     | 
| 
       107 
112 
     | 
    
         
             
              string_literal: (path, { preferSingleQuotes }, print) => {
         
     | 
| 
       108 
113 
     | 
    
         
             
                const string = path.getValue().body[0];
         
     | 
| 
       109 
114 
     | 
    
         | 
| 
         @@ -142,21 +147,6 @@ module.exports = { 
     | 
|
| 
       142 
147 
     | 
    
         
             
              xstring_literal: (path, opts, print) => {
         
     | 
| 
       143 
148 
     | 
    
         
             
                const parts = path.call(print, "body", 0);
         
     | 
| 
       144 
149 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
                 
     | 
| 
       146 
     | 
    
         
            -
                  parts[0] = parts[0].replace(/^\s+/, "");
         
     | 
| 
       147 
     | 
    
         
            -
                }
         
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
                const lastIndex = parts.length - 1;
         
     | 
| 
       150 
     | 
    
         
            -
                if (typeof parts[lastIndex] === "string") {
         
     | 
| 
       151 
     | 
    
         
            -
                  parts[lastIndex] = parts[lastIndex].replace(/\s+$/, "");
         
     | 
| 
       152 
     | 
    
         
            -
                }
         
     | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
       154 
     | 
    
         
            -
                return group(
         
     | 
| 
       155 
     | 
    
         
            -
                  concat([
         
     | 
| 
       156 
     | 
    
         
            -
                    "`",
         
     | 
| 
       157 
     | 
    
         
            -
                    indent(concat([softline, join(softline, parts)])),
         
     | 
| 
       158 
     | 
    
         
            -
                    concat([softline, "`"])
         
     | 
| 
       159 
     | 
    
         
            -
                  ])
         
     | 
| 
       160 
     | 
    
         
            -
                );
         
     | 
| 
      
 150 
     | 
    
         
            +
                return concat(["`"].concat(parts).concat("`"));
         
     | 
| 
       161 
151 
     | 
    
         
             
              }
         
     | 
| 
       162 
152 
     | 
    
         
             
            };
         
     | 
    
        data/src/ripper.rb
    CHANGED
    
    | 
         @@ -340,7 +340,8 @@ class RipperJS < Ripper 
     | 
|
| 
       340 
340 
     | 
    
         
             
                  (SCANNER_EVENTS - defined).each do |event|
         
     | 
| 
       341 
341 
     | 
    
         
             
                    define_method(:"on_#{event}") do |body|
         
     | 
| 
       342 
342 
     | 
    
         
             
                      super(body).tap do |node|
         
     | 
| 
       343 
     | 
    
         
            -
                         
     | 
| 
      
 343 
     | 
    
         
            +
                        char_end = char_pos + (body ? body.size : 0)
         
     | 
| 
      
 344 
     | 
    
         
            +
                        node.merge!(char_start: char_pos, char_end: char_end)
         
     | 
| 
       344 
345 
     | 
    
         | 
| 
       345 
346 
     | 
    
         
             
                        scanner_events << node
         
     | 
| 
       346 
347 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -678,7 +679,7 @@ class RipperJS < Ripper 
     | 
|
| 
       678 
679 
     | 
    
         | 
| 
       679 
680 
     | 
    
         
             
                    super(ident).tap do |node|
         
     | 
| 
       680 
681 
     | 
    
         
             
                      if !@access_controls.include?(ident[:body]) ||
         
     | 
| 
       681 
     | 
    
         
            -
             
     | 
| 
      
 682 
     | 
    
         
            +
                           ident[:body] != lines[lineno - 1].strip
         
     | 
| 
       682 
683 
     | 
    
         
             
                        next
         
     | 
| 
       683 
684 
     | 
    
         
             
                      end
         
     | 
| 
       684 
685 
     | 
    
         | 
| 
         @@ -713,7 +714,7 @@ class RipperJS < Ripper 
     | 
|
| 
       713 
714 
     | 
    
         
             
                    stmts, *other_parts = bodystmt[:body]
         
     | 
| 
       714 
715 
     | 
    
         | 
| 
       715 
716 
     | 
    
         
             
                    if !other_parts.any? && stmts[:body].length == 1 &&
         
     | 
| 
       716 
     | 
    
         
            -
             
     | 
| 
      
 717 
     | 
    
         
            +
                         stmts.dig(:body, 0, :type) == :begin
         
     | 
| 
       717 
718 
     | 
    
         
             
                      def_bodystmt = stmts.dig(:body, 0, :body, 0)
         
     | 
| 
       718 
719 
     | 
    
         
             
                    end
         
     | 
| 
       719 
720 
     | 
    
         | 
    
        data/src/utils.js
    CHANGED
    
    | 
         @@ -8,6 +8,12 @@ const { 
     | 
|
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            const concatBody = (path, opts, print) => concat(path.map(print, "body"));
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
            // If the node is a type of assignment or if the node is a paren and nested
         
     | 
| 
      
 12 
     | 
    
         
            +
            // inside that paren is a node that is a type of assignment.
         
     | 
| 
      
 13 
     | 
    
         
            +
            const containsAssignment = node =>
         
     | 
| 
      
 14 
     | 
    
         
            +
              ["assign", "massign"].includes(node.type) ||
         
     | 
| 
      
 15 
     | 
    
         
            +
              (node.type === "paren" && node.body[0].body.some(containsAssignment));
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
       11 
17 
     | 
    
         
             
            const docLength = doc => {
         
     | 
| 
       12 
18 
     | 
    
         
             
              if (doc.length) {
         
     | 
| 
       13 
19 
     | 
    
         
             
                return doc.length;
         
     | 
| 
         @@ -135,6 +141,7 @@ const surround = (left, right) => (path, opts, print) => 
     | 
|
| 
       135 
141 
     | 
    
         | 
| 
       136 
142 
     | 
    
         
             
            module.exports = {
         
     | 
| 
       137 
143 
     | 
    
         
             
              concatBody,
         
     | 
| 
      
 144 
     | 
    
         
            +
              containsAssignment,
         
     | 
| 
       138 
145 
     | 
    
         
             
              docLength,
         
     | 
| 
       139 
146 
     | 
    
         
             
              empty,
         
     | 
| 
       140 
147 
     | 
    
         
             
              first,
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: prettier
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.15. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.15.1
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Kevin Deisz
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2019- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2019-11-05 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: bundler
         
     | 
| 
         @@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       126 
126 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       127 
127 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       128 
128 
     | 
    
         
             
            requirements: []
         
     | 
| 
       129 
     | 
    
         
            -
            rubygems_version: 3.0. 
     | 
| 
      
 129 
     | 
    
         
            +
            rubygems_version: 3.0.6
         
     | 
| 
       130 
130 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       131 
131 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       132 
132 
     | 
    
         
             
            summary: prettier plugin for the Ruby programming language
         
     |