prettier 1.5.1 → 1.6.0

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 +55 -2
  3. data/CONTRIBUTING.md +2 -2
  4. data/README.md +41 -12
  5. data/node_modules/prettier/bin-prettier.js +13702 -11629
  6. data/node_modules/prettier/index.js +19191 -16565
  7. data/node_modules/prettier/parser-angular.js +67 -0
  8. data/node_modules/prettier/parser-babel.js +22 -0
  9. data/node_modules/prettier/parser-espree.js +22 -0
  10. data/node_modules/prettier/parser-flow.js +22 -0
  11. data/node_modules/prettier/parser-glimmer.js +1 -0
  12. data/node_modules/prettier/parser-graphql.js +1 -0
  13. data/node_modules/prettier/parser-html.js +132 -0
  14. data/node_modules/prettier/parser-markdown.js +34 -0
  15. data/node_modules/prettier/parser-meriyah.js +22 -0
  16. data/node_modules/prettier/parser-postcss.js +22 -0
  17. data/node_modules/prettier/parser-typescript.js +22 -0
  18. data/node_modules/prettier/parser-yaml.js +15 -0
  19. data/node_modules/prettier/third-party.js +1042 -833
  20. data/package.json +5 -5
  21. data/rubocop.yml +12 -0
  22. data/src/haml/parser.js +6 -5
  23. data/src/haml/parser.rb +8 -3
  24. data/src/haml/printer.js +428 -18
  25. data/src/parser/netcat.js +0 -2
  26. data/src/parser/parseSync.js +153 -14
  27. data/src/parser/server.rb +7 -2
  28. data/src/plugin.js +7 -1
  29. data/src/rbs/parser.js +3 -5
  30. data/src/rbs/parser.rb +7 -3
  31. data/src/rbs/printer.js +46 -8
  32. data/src/ruby/embed.js +7 -5
  33. data/src/ruby/nodes/args.js +111 -19
  34. data/src/ruby/nodes/calls.js +8 -1
  35. data/src/ruby/nodes/conditionals.js +47 -45
  36. data/src/ruby/nodes/hashes.js +5 -14
  37. data/src/ruby/nodes/heredocs.js +5 -3
  38. data/src/ruby/nodes/params.js +2 -9
  39. data/src/ruby/nodes/strings.js +95 -2
  40. data/src/ruby/parser.js +3 -5
  41. data/src/ruby/parser.rb +82 -31
  42. data/src/ruby/printer.js +10 -1
  43. data/src/utils.js +1 -1
  44. data/src/utils/inlineEnsureParens.js +1 -0
  45. data/src/utils/literallineWithoutBreakParent.js +7 -0
  46. data/src/utils/skipAssignIndent.js +8 -1
  47. metadata +15 -15
  48. data/src/haml/nodes/comment.js +0 -27
  49. data/src/haml/nodes/doctype.js +0 -34
  50. data/src/haml/nodes/filter.js +0 -16
  51. data/src/haml/nodes/hamlComment.js +0 -21
  52. data/src/haml/nodes/plain.js +0 -6
  53. data/src/haml/nodes/root.js +0 -8
  54. data/src/haml/nodes/script.js +0 -33
  55. data/src/haml/nodes/silentScript.js +0 -59
  56. data/src/haml/nodes/tag.js +0 -193
  57. data/src/parser/getLang.js +0 -32
  58. data/src/parser/getNetcat.js +0 -50
  59. data/src/parser/requestParse.js +0 -74
  60. data/src/utils/literalLineNoBreak.js +0 -7
@@ -4,6 +4,7 @@ const {
4
4
  hardline,
5
5
  ifBreak,
6
6
  indent,
7
+ join,
7
8
  softline
8
9
  } = require("../../prettier");
9
10
  const { makeCall, noIndent } = require("../../utils");
@@ -133,7 +134,13 @@ function printMethodAddArg(path, opts, print) {
133
134
  );
134
135
  }
135
136
 
136
- return concat([methodDoc, argsDoc]);
137
+ // If there are already parentheses, then we can just use the doc that's
138
+ // already printed.
139
+ if (argNode.type == "arg_paren") {
140
+ return concat([methodDoc, argsDoc]);
141
+ }
142
+
143
+ return concat([methodDoc, " ", join(", ", argsDoc), " "]);
137
144
  }
138
145
 
139
146
  function printMethodAddBlock(path, opts, print) {
@@ -190,57 +190,59 @@ const canTernary = (path) => {
190
190
  };
191
191
 
192
192
  // A normalized print function for both `if` and `unless` nodes.
193
- const printConditional = (keyword) => (path, { rubyModifier }, print) => {
194
- if (canTernary(path)) {
195
- let ternaryParts = [path.call(print, "body", 0), " ? "].concat(
196
- printTernaryClauses(
197
- keyword,
198
- path.call(print, "body", 1),
199
- path.call(print, "body", 2, "body", 0)
200
- )
201
- );
202
-
203
- if (["binary", "call"].includes(path.getParentNode().type)) {
204
- ternaryParts = ["("].concat(ternaryParts).concat(")");
193
+ const printConditional =
194
+ (keyword) =>
195
+ (path, { rubyModifier }, print) => {
196
+ if (canTernary(path)) {
197
+ let ternaryParts = [path.call(print, "body", 0), " ? "].concat(
198
+ printTernaryClauses(
199
+ keyword,
200
+ path.call(print, "body", 1),
201
+ path.call(print, "body", 2, "body", 0)
202
+ )
203
+ );
204
+
205
+ if (["binary", "call"].includes(path.getParentNode().type)) {
206
+ ternaryParts = ["("].concat(ternaryParts).concat(")");
207
+ }
208
+
209
+ return group(
210
+ ifBreak(printWithAddition(keyword, path, print), concat(ternaryParts))
211
+ );
205
212
  }
206
213
 
207
- return group(
208
- ifBreak(printWithAddition(keyword, path, print), concat(ternaryParts))
209
- );
210
- }
211
-
212
- const [predicate, statements, addition] = path.getValue().body;
214
+ const [predicate, statements, addition] = path.getValue().body;
213
215
 
214
- // If there's an additional clause that wasn't matched earlier, we know we
215
- // can't go for the inline option.
216
- if (addition) {
217
- return group(printWithAddition(keyword, path, print, { breaking: true }));
218
- }
216
+ // If there's an additional clause that wasn't matched earlier, we know we
217
+ // can't go for the inline option.
218
+ if (addition) {
219
+ return group(printWithAddition(keyword, path, print, { breaking: true }));
220
+ }
219
221
 
220
- // If the body of the conditional is empty, then we explicitly have to use the
221
- // block form.
222
- if (isEmptyStmts(statements)) {
223
- return concat([
224
- `${keyword} `,
225
- align(keyword.length + 1, path.call(print, "body", 0)),
226
- concat([hardline, "end"])
227
- ]);
228
- }
222
+ // If the body of the conditional is empty, then we explicitly have to use the
223
+ // block form.
224
+ if (isEmptyStmts(statements)) {
225
+ return concat([
226
+ `${keyword} `,
227
+ align(keyword.length + 1, path.call(print, "body", 0)),
228
+ concat([hardline, "end"])
229
+ ]);
230
+ }
229
231
 
230
- // If the predicate of the conditional contains an assignment, then we can't
231
- // know for sure that it doesn't impact the body of the conditional, so we
232
- // have to default to the block form.
233
- if (containsAssignment(predicate)) {
234
- return concat([
235
- `${keyword} `,
236
- align(keyword.length + 1, path.call(print, "body", 0)),
237
- indent(concat([hardline, path.call(print, "body", 1)])),
238
- concat([hardline, "end"])
239
- ]);
240
- }
232
+ // If the predicate of the conditional contains an assignment, then we can't
233
+ // know for sure that it doesn't impact the body of the conditional, so we
234
+ // have to default to the block form.
235
+ if (containsAssignment(predicate)) {
236
+ return concat([
237
+ `${keyword} `,
238
+ align(keyword.length + 1, path.call(print, "body", 0)),
239
+ indent(concat([hardline, path.call(print, "body", 1)])),
240
+ concat([hardline, "end"])
241
+ ]);
242
+ }
241
243
 
242
- return printSingle(keyword)(path, { rubyModifier }, print);
243
- };
244
+ return printSingle(keyword)(path, { rubyModifier }, print);
245
+ };
244
246
 
245
247
  module.exports = {
246
248
  else: (path, opts, print) => {
@@ -56,28 +56,19 @@ function printHashKeyLabel(path, print) {
56
56
  case "symbol_literal":
57
57
  return concat([path.call(print, "body", 0), ":"]);
58
58
  case "dyna_symbol": {
59
- const { parts } = print(path);
60
-
61
- // We're going to slice off the starting colon character so that we can
62
- // move it to the end. If there are comments, then we're going to go
63
- // further into the printed doc nodes.
64
- if (parts[0] === ":") {
65
- parts.splice(0, 1);
66
- } else {
67
- parts[1].parts.splice(0, 1);
68
- }
69
-
70
- return concat(parts.concat(":"));
59
+ return concat([print(path), ":"]);
71
60
  }
72
61
  }
73
62
  }
74
63
 
75
64
  function printHashKeyRocket(path, print) {
76
65
  const node = path.getValue();
77
- const doc = print(path);
66
+ let doc = print(path);
78
67
 
79
68
  if (node.type === "@label") {
80
- return `:${doc.slice(0, doc.length - 1)} =>`;
69
+ doc = concat([":", doc.slice(0, doc.length - 1)]);
70
+ } else if (node.type === "dyna_symbol") {
71
+ doc = concat([":", doc]);
81
72
  }
82
73
 
83
74
  return concat([doc, " =>"]);
@@ -1,5 +1,5 @@
1
1
  const { concat, group, lineSuffix, join } = require("../../prettier");
2
- const { literalLineNoBreak } = require("../../utils");
2
+ const { literallineWithoutBreakParent } = require("../../utils");
3
3
 
4
4
  function printHeredoc(path, opts, print) {
5
5
  const { body, ending } = path.getValue();
@@ -11,7 +11,7 @@ function printHeredoc(path, opts, print) {
11
11
  }
12
12
 
13
13
  // In this case, the part of the string is just regular string content
14
- return join(literalLineNoBreak, part.body.split("\n"));
14
+ return join(literallineWithoutBreakParent, part.body.split("\n"));
15
15
  });
16
16
 
17
17
  // We use a literalline break because matching indentation is required
@@ -23,7 +23,9 @@ function printHeredoc(path, opts, print) {
23
23
  concat([
24
24
  path.call(print, "beging"),
25
25
  lineSuffix(
26
- group(concat([literalLineNoBreak].concat(parts).concat(ending)))
26
+ group(
27
+ concat([literallineWithoutBreakParent].concat(parts).concat(ending))
28
+ )
27
29
  )
28
30
  ])
29
31
  );
@@ -17,15 +17,8 @@ function printRestParam(symbol) {
17
17
  }
18
18
 
19
19
  function printParams(path, opts, print) {
20
- const [
21
- reqs,
22
- optls,
23
- rest,
24
- post,
25
- kwargs,
26
- kwargRest,
27
- block
28
- ] = path.getValue().body;
20
+ const [reqs, optls, rest, post, kwargs, kwargRest, block] =
21
+ path.getValue().body;
29
22
  let parts = [];
30
23
 
31
24
  if (reqs) {
@@ -82,13 +82,106 @@ function printChar(path, { rubySingleQuote }, _print) {
82
82
  return concat([quote, body.slice(1), quote]);
83
83
  }
84
84
 
85
+ function printPercentSDynaSymbol(path, opts, print) {
86
+ const node = path.getValue();
87
+ const parts = [];
88
+
89
+ // Push on the quote, which includes the opening character.
90
+ parts.push(node.quote);
91
+
92
+ path.each((childPath) => {
93
+ const childNode = childPath.getValue();
94
+
95
+ if (childNode.type !== "@tstring_content") {
96
+ // Here we are printing an embedded variable or expression.
97
+ parts.push(print(childPath));
98
+ } else {
99
+ // Here we are printing plain string content.
100
+ parts.push(join(literalline, childNode.body.split("\n")));
101
+ }
102
+ }, "body");
103
+
104
+ // Push on the closing character, which is the opposite of the third
105
+ // character from the opening.
106
+ parts.push(quotePairs[node.quote[2]]);
107
+
108
+ return concat(parts);
109
+ }
110
+
111
+ // We don't actually want to print %s symbols, as they're much more rarely seen
112
+ // in the wild. But we're going to be forced into it if it's a multi-line symbol
113
+ // or if the quoting would get super complicated.
114
+ function shouldPrintPercentSDynaSymbol(node) {
115
+ // We shouldn't print a %s dyna symbol if it was not already that way in the
116
+ // original source.
117
+ if (node.quote[0] !== "%") {
118
+ return false;
119
+ }
120
+
121
+ // Here we're going to check if there is a closing character, a new line, or a
122
+ // quote in the content of the dyna symbol. If there is, then quoting could
123
+ // get weird, so just bail out and stick to the original bounds in the source.
124
+ const closing = quotePairs[node.quote[2]];
125
+
126
+ return node.body.some(
127
+ (child) =>
128
+ child.type === "@tstring_content" &&
129
+ (child.body.includes("\n") ||
130
+ child.body.includes(closing) ||
131
+ child.body.includes("'") ||
132
+ child.body.includes('"'))
133
+ );
134
+ }
135
+
85
136
  // Prints a dynamic symbol. Assumes there's a quote property attached to the
86
137
  // node that will tell us which quote to use when printing. We're just going to
87
138
  // use whatever quote was provided.
139
+ //
140
+ // In the case of a plain dyna symbol, node.quote will be either :" or :'
141
+ // For %s dyna symbols, node.quote will be %s[, %s(, %s{, or %s<
88
142
  function printDynaSymbol(path, opts, print) {
89
- const { quote } = path.getValue();
143
+ const node = path.getValue();
144
+
145
+ if (shouldPrintPercentSDynaSymbol(node)) {
146
+ return printPercentSDynaSymbol(path, opts, print);
147
+ }
148
+
149
+ const parts = [];
150
+ let quote;
151
+
152
+ if (isQuoteLocked(node)) {
153
+ if (node.quote.startsWith("%")) {
154
+ quote = opts.rubySingleQuote ? "'" : '"';
155
+ } else {
156
+ quote = node.quote.slice(1);
157
+ }
158
+ } else {
159
+ quote = opts.rubySingleQuote && isSingleQuotable(node) ? "'" : '"';
160
+ }
161
+
162
+ parts.push(quote);
163
+ path.each((childPath) => {
164
+ const child = childPath.getValue();
165
+
166
+ if (child.type !== "@tstring_content") {
167
+ parts.push(print(childPath));
168
+ } else {
169
+ parts.push(
170
+ join(literalline, normalizeQuotes(child.body, quote).split("\n"))
171
+ );
172
+ }
173
+ }, "body");
174
+
175
+ parts.push(quote);
176
+
177
+ // If we're inside of an assoc_new node as the key, then it will handle
178
+ // printing the : on its own since it could change sides.
179
+ const parentNode = path.getParentNode();
180
+ if (parentNode.type !== "assoc_new" || parentNode.body[0] !== node) {
181
+ parts.unshift(":");
182
+ }
90
183
 
91
- return concat([":", quote].concat(path.map(print, "body")).concat(quote));
184
+ return concat(parts);
92
185
  }
93
186
 
94
187
  function printStringConcat(path, opts, print) {
data/src/ruby/parser.js CHANGED
@@ -4,16 +4,14 @@ const parseSync = require("../parser/parseSync");
4
4
  // to prettier a JavaScript object that is the equivalent AST that represents
5
5
  // the code stored in that string. We accomplish this by spawning a new Ruby
6
6
  // process of parser.rb and reading JSON off STDOUT.
7
- function parse(text, _parsers, _opts) {
8
- return parseSync("ruby", text);
7
+ function parse(text, _parsers, opts) {
8
+ return parseSync("ruby", text, opts);
9
9
  }
10
10
 
11
- const pragmaPattern = /#\s*@(prettier|format)/;
12
-
13
11
  // This function handles checking whether or not the source string has the
14
12
  // pragma for prettier. This is an optional workflow for incremental adoption.
15
13
  function hasPragma(text) {
16
- return pragmaPattern.test(text);
14
+ return /^\s*#[^\S\n]*@(format|prettier)\s*(\n|$)/.test(text);
17
15
  }
18
16
 
19
17
  // This function is critical for comments and cursor support, and is responsible
data/src/ruby/parser.rb CHANGED
@@ -13,8 +13,7 @@ if (RUBY_MAJOR < 2) || ((RUBY_MAJOR == 2) && (RUBY_MINOR < 5))
13
13
  exit 1
14
14
  end
15
15
 
16
- require 'delegate'
17
- require 'json'
16
+ require 'json' unless defined?(JSON)
18
17
  require 'ripper'
19
18
 
20
19
  module Prettier
@@ -54,6 +53,35 @@ class Prettier::Parser < Ripper
54
53
  end
55
54
  end
56
55
 
56
+ # This is a small wrapper around the value of a node for those specific events
57
+ # that need extra handling. (For example: statement, body statement, and
58
+ # rescue nodes which all need extra information to determine their character
59
+ # boundaries.)
60
+ class Node
61
+ attr_reader :parser, :value
62
+
63
+ def initialize(parser, value)
64
+ @parser = parser
65
+ @value = value
66
+ end
67
+
68
+ def [](key)
69
+ value[key]
70
+ end
71
+
72
+ def dig(*keys)
73
+ value.dig(*keys)
74
+ end
75
+
76
+ def to_json(*opts)
77
+ value.to_json(*opts)
78
+ end
79
+
80
+ def pretty_print(q)
81
+ q.pp_hash(self)
82
+ end
83
+ end
84
+
57
85
  attr_reader :source, :lines, :scanner_events
58
86
 
59
87
  # This is an attr_accessor so Stmts objects can grab comments out of this
@@ -565,6 +593,12 @@ class Prettier::Parser < Ripper
565
593
  # binary is a parser event that represents a binary operation between two
566
594
  # values.
567
595
  def on_binary(left, oper, right)
596
+ # On most Ruby implementations, oper is a Symbol that represents that
597
+ # operation being performed. For instance in the example `1 < 2`, the `oper`
598
+ # object would be `:<`. However, on JRuby, it's an `@op` node, so here we're
599
+ # going to explicitly convert it into the same normalized form.
600
+ oper = scanner_events.delete(oper)[:body] unless oper.is_a?(Symbol)
601
+
568
602
  {
569
603
  type: :binary,
570
604
  body: [left, oper, right],
@@ -611,19 +645,19 @@ class Prettier::Parser < Ripper
611
645
  # bodystmt can't actually determine its bounds appropriately because it
612
646
  # doesn't necessarily know where it started. So the parent node needs to
613
647
  # report back down into this one where it goes.
614
- class BodyStmt < SimpleDelegator
648
+ class BodyStmt < Node
615
649
  def bind(sc, ec)
616
- merge!(sc: sc, ec: ec)
617
- parts = self[:body]
650
+ value.merge!(sc: sc, ec: ec)
651
+ parts = value[:body]
618
652
 
619
653
  # Here we're going to determine the bounds for the stmts
620
654
  consequent = parts[1..-1].compact.first
621
- self[:body][0].bind(sc, consequent ? consequent[:sc] : ec)
655
+ value[:body][0].bind(sc, consequent ? consequent[:sc] : ec)
622
656
 
623
657
  # Next we're going to determine the rescue clause if there is one
624
658
  if parts[1]
625
659
  consequent = parts[2..-1].compact.first
626
- self[:body][1].bind_end(consequent ? consequent[:sc] : ec)
660
+ value[:body][1].bind_end(consequent ? consequent[:sc] : ec)
627
661
  end
628
662
  end
629
663
  end
@@ -632,6 +666,7 @@ class Prettier::Parser < Ripper
632
666
  # of clauses within the body of a method or block.
633
667
  def on_bodystmt(stmts, rescued, ensured, elsed)
634
668
  BodyStmt.new(
669
+ self,
635
670
  type: :bodystmt,
636
671
  body: [stmts, rescued, ensured, elsed],
637
672
  sl: lineno,
@@ -656,7 +691,7 @@ class Prettier::Parser < Ripper
656
691
  body: [block_var, stmts],
657
692
  sl: beging[:sl],
658
693
  sc: beging[:sc],
659
- el: ending[:el],
694
+ el: [ending[:el], stmts[:el]].max,
660
695
  ec: ending[:ec]
661
696
  }
662
697
  end
@@ -709,7 +744,7 @@ class Prettier::Parser < Ripper
709
744
  body: [receiver, oper, sending],
710
745
  sl: receiver[:sl],
711
746
  sc: receiver[:sc],
712
- el: ending[:el],
747
+ el: [ending[:el], receiver[:el]].max,
713
748
  ec: ending[:ec]
714
749
  }
715
750
  end
@@ -1057,7 +1092,7 @@ class Prettier::Parser < Ripper
1057
1092
 
1058
1093
  beging.merge(
1059
1094
  type: :dyna_symbol,
1060
- quote: beging[:body][1],
1095
+ quote: beging[:body],
1061
1096
  body: string[:body],
1062
1097
  el: ending[:el],
1063
1098
  ec: ending[:ec]
@@ -1723,6 +1758,28 @@ class Prettier::Parser < Ripper
1723
1758
  )
1724
1759
  end
1725
1760
 
1761
+ # A special parser error so that we can get nice syntax displays on the error
1762
+ # message when prettier prints out the results.
1763
+ class ParserError < StandardError
1764
+ attr_reader :lineno, :column
1765
+
1766
+ def initialize(error, lineno, column)
1767
+ super(error)
1768
+ @lineno = lineno
1769
+ @column = column
1770
+ end
1771
+ end
1772
+
1773
+ # If we encounter a parse error, just immediately bail out so that our runner
1774
+ # can catch it.
1775
+ def on_parse_error(error, *)
1776
+ raise ParserError.new(error, lineno, column)
1777
+ end
1778
+ alias on_alias_error on_parse_error
1779
+ alias on_assign_error on_parse_error
1780
+ alias on_class_name_error on_parse_error
1781
+ alias on_param_error on_parse_error
1782
+
1726
1783
  # The program node is the very top of the AST. Here we'll attach all of
1727
1784
  # the comments that we've gathered up over the course of parsing the
1728
1785
  # source string. We'll also attach on the __END__ content if there was
@@ -1817,12 +1874,12 @@ class Prettier::Parser < Ripper
1817
1874
  # doesn't really have all of the information that it needs in order to
1818
1875
  # determine its ending. Therefore it relies on its parent bodystmt node to
1819
1876
  # report its ending to it.
1820
- class Rescue < SimpleDelegator
1877
+ class Rescue < Node
1821
1878
  def bind_end(ec)
1822
- merge!(ec: ec)
1879
+ value.merge!(ec: ec)
1823
1880
 
1824
- stmts = self[:body][1]
1825
- consequent = self[:body][2]
1881
+ stmts = value[:body][1]
1882
+ consequent = value[:body][2]
1826
1883
 
1827
1884
  if consequent
1828
1885
  consequent.bind_end(ec)
@@ -1858,6 +1915,7 @@ class Prettier::Parser < Ripper
1858
1915
  end
1859
1916
 
1860
1917
  Rescue.new(
1918
+ self,
1861
1919
  beging.merge!(
1862
1920
  type: :rescue,
1863
1921
  body: [rescue_ex, stmts, consequent],
@@ -1958,36 +2016,29 @@ class Prettier::Parser < Ripper
1958
2016
  # stmts nodes will report back down the location information. We then
1959
2017
  # propagate that onto void_stmt nodes inside the stmts in order to make sure
1960
2018
  # all comments get printed appropriately.
1961
- class Stmts < SimpleDelegator
1962
- attr_reader :parser
1963
-
1964
- def initialize(parser, values)
1965
- @parser = parser
1966
- __setobj__(values)
1967
- end
1968
-
2019
+ class Stmts < Node
1969
2020
  def bind(sc, ec)
1970
- merge!(sc: sc, ec: ec)
2021
+ value.merge!(sc: sc, ec: ec)
1971
2022
 
1972
- if self[:body][0][:type] == :void_stmt
1973
- self[:body][0].merge!(sc: sc, ec: sc)
2023
+ if value[:body][0][:type] == :void_stmt
2024
+ value[:body][0].merge!(sc: sc, ec: sc)
1974
2025
  end
1975
2026
 
1976
2027
  attach_comments(sc, ec)
1977
2028
  end
1978
2029
 
1979
2030
  def bind_end(ec)
1980
- merge!(ec: ec)
2031
+ value.merge!(ec: ec)
1981
2032
  end
1982
2033
 
1983
2034
  def <<(statement)
1984
- if self[:body].any?
1985
- merge!(statement.slice(:el, :ec))
2035
+ if value[:body].any?
2036
+ value.merge!(statement.slice(:el, :ec))
1986
2037
  else
1987
- merge!(statement.slice(:sl, :el, :sc, :ec))
2038
+ value.merge!(statement.slice(:sl, :el, :sc, :ec))
1988
2039
  end
1989
2040
 
1990
- self[:body] << statement
2041
+ value[:body] << statement
1991
2042
  self
1992
2043
  end
1993
2044
 
@@ -2004,7 +2055,7 @@ class Prettier::Parser < Ripper
2004
2055
  return if attachable.empty?
2005
2056
 
2006
2057
  parser.comments -= attachable
2007
- self[:body] = (self[:body] + attachable).sort_by! { |node| node[:sc] }
2058
+ value[:body] = (value[:body] + attachable).sort_by! { |node| node[:sc] }
2008
2059
  end
2009
2060
  end
2010
2061