prettier 1.5.2 → 1.6.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -1
  3. data/CONTRIBUTING.md +2 -2
  4. data/README.md +41 -12
  5. data/node_modules/prettier/bin-prettier.js +13848 -11589
  6. data/node_modules/prettier/doc.js +4961 -0
  7. data/node_modules/prettier/index.js +19466 -16783
  8. data/node_modules/prettier/package.json +23 -0
  9. data/node_modules/prettier/parser-angular.js +67 -0
  10. data/node_modules/prettier/parser-babel.js +22 -0
  11. data/node_modules/prettier/parser-espree.js +22 -0
  12. data/node_modules/prettier/parser-flow.js +22 -0
  13. data/node_modules/prettier/parser-glimmer.js +1 -0
  14. data/node_modules/prettier/parser-graphql.js +1 -0
  15. data/node_modules/prettier/parser-html.js +132 -0
  16. data/node_modules/prettier/parser-markdown.js +34 -0
  17. data/node_modules/prettier/parser-meriyah.js +22 -0
  18. data/node_modules/prettier/parser-postcss.js +22 -0
  19. data/node_modules/prettier/parser-typescript.js +22 -0
  20. data/node_modules/prettier/parser-yaml.js +15 -0
  21. data/node_modules/prettier/third-party.js +1671 -864
  22. data/package.json +5 -5
  23. data/rubocop.yml +12 -0
  24. data/src/haml/parser.js +6 -5
  25. data/src/haml/parser.rb +8 -3
  26. data/src/haml/printer.js +428 -18
  27. data/src/parser/netcat.js +0 -2
  28. data/src/parser/parseSync.js +153 -14
  29. data/src/parser/server.rb +5 -0
  30. data/src/plugin.js +7 -1
  31. data/src/rbs/parser.js +3 -5
  32. data/src/rbs/parser.rb +7 -3
  33. data/src/rbs/printer.js +46 -8
  34. data/src/ruby/nodes/args.js +111 -19
  35. data/src/ruby/nodes/calls.js +50 -3
  36. data/src/ruby/nodes/conditionals.js +47 -45
  37. data/src/ruby/nodes/hashes.js +5 -14
  38. data/src/ruby/nodes/params.js +2 -9
  39. data/src/ruby/nodes/strings.js +97 -2
  40. data/src/ruby/parser.js +3 -5
  41. data/src/ruby/parser.rb +76 -31
  42. data/src/ruby/printer.js +10 -1
  43. data/src/utils/inlineEnsureParens.js +1 -0
  44. data/src/utils/noIndent.js +0 -1
  45. data/src/utils/skipAssignIndent.js +8 -1
  46. metadata +16 -14
  47. data/src/haml/nodes/comment.js +0 -27
  48. data/src/haml/nodes/doctype.js +0 -34
  49. data/src/haml/nodes/filter.js +0 -16
  50. data/src/haml/nodes/hamlComment.js +0 -21
  51. data/src/haml/nodes/plain.js +0 -6
  52. data/src/haml/nodes/root.js +0 -8
  53. data/src/haml/nodes/script.js +0 -33
  54. data/src/haml/nodes/silentScript.js +0 -59
  55. data/src/haml/nodes/tag.js +0 -193
  56. data/src/parser/getLang.js +0 -32
  57. data/src/parser/getNetcat.js +0 -50
  58. data/src/parser/requestParse.js +0 -74
@@ -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");
@@ -32,12 +33,23 @@ function printCall(path, opts, print) {
32
33
 
33
34
  // The right side of the call node, as in everything including the operator
34
35
  // and beyond.
35
- const rightSideDoc = concat([
36
+ let rightSideDoc = concat([
36
37
  receiverNode.comments ? hardline : softline,
37
38
  operatorDoc,
38
39
  messageDoc
39
40
  ]);
40
41
 
42
+ // This is very specialized behavior wherein we group .where.not calls
43
+ // together because it looks better. For more information, see
44
+ // https://github.com/prettier/plugin-ruby/issues/862.
45
+ if (
46
+ receiverNode.type === "call" &&
47
+ receiverNode.body[2].body === "where" &&
48
+ messageDoc === "not"
49
+ ) {
50
+ rightSideDoc = concat([operatorDoc, messageDoc]);
51
+ }
52
+
41
53
  // Get a reference to the parent node so we can check if we're inside a chain
42
54
  const parentNode = path.getParentNode();
43
55
 
@@ -109,9 +121,38 @@ function printMethodAddArg(path, opts, print) {
109
121
  parentNode.firstReceiverType = node.firstReceiverType;
110
122
  }
111
123
 
124
+ // This is the threshold at which we will start to try to make a nicely
125
+ // indented call chain. For the most part, it's always 3.
126
+ let threshold = 3;
127
+
128
+ // Here, we have very specialized behavior where if we're within a sig block,
129
+ // then we're going to assume we're creating a Sorbet type signature. In that
130
+ // case, we really want the threshold to be lowered to 2 so that we create
131
+ // method chains off of any two method calls within the block. For more
132
+ // details, see
133
+ // https://github.com/prettier/plugin-ruby/issues/863.
134
+ let sigBlock = path.getParentNode(2);
135
+ if (sigBlock) {
136
+ // If we're at a do_block, then we want to go one more level up. This is
137
+ // because do_blocks have bodystmt nodes instead of just stmt nodes.
138
+ if (sigBlock.type === "do_block") {
139
+ sigBlock = path.getParentNode(3);
140
+ }
141
+
142
+ if (
143
+ sigBlock.type === "method_add_block" &&
144
+ sigBlock.body[1] &&
145
+ sigBlock.body[0].type === "method_add_arg" &&
146
+ sigBlock.body[0].body[0].type === "fcall" &&
147
+ sigBlock.body[0].body[0].body[0].body === "sig"
148
+ ) {
149
+ threshold = 2;
150
+ }
151
+ }
152
+
112
153
  // If we're at the top of a chain, then we're going to print out a nice
113
154
  // multi-line layout if this doesn't break into multiple lines.
114
- if (!chained.includes(parentNode.type) && (node.chain || 0) >= 3) {
155
+ if (!chained.includes(parentNode.type) && (node.chain || 0) >= threshold) {
115
156
  // This is pretty specialized behavior. Basically if we're at the top of a
116
157
  // chain but we've only had method calls without arguments and now we have
117
158
  // arguments, then we're effectively trying to call a method with arguments
@@ -133,7 +174,13 @@ function printMethodAddArg(path, opts, print) {
133
174
  );
134
175
  }
135
176
 
136
- return concat([methodDoc, argsDoc]);
177
+ // If there are already parentheses, then we can just use the doc that's
178
+ // already printed.
179
+ if (argNode.type == "arg_paren") {
180
+ return concat([methodDoc, argsDoc]);
181
+ }
182
+
183
+ return concat([methodDoc, " ", join(", ", argsDoc), " "]);
137
184
  }
138
185
 
139
186
  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, " =>"]);
@@ -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,108 @@ 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 if (node.quote.startsWith(":")) {
156
+ quote = node.quote.slice(1);
157
+ } else {
158
+ quote = node.quote;
159
+ }
160
+ } else {
161
+ quote = opts.rubySingleQuote && isSingleQuotable(node) ? "'" : '"';
162
+ }
163
+
164
+ parts.push(quote);
165
+ path.each((childPath) => {
166
+ const child = childPath.getValue();
167
+
168
+ if (child.type !== "@tstring_content") {
169
+ parts.push(print(childPath));
170
+ } else {
171
+ parts.push(
172
+ join(literalline, normalizeQuotes(child.body, quote).split("\n"))
173
+ );
174
+ }
175
+ }, "body");
176
+
177
+ parts.push(quote);
178
+
179
+ // If we're inside of an assoc_new node as the key, then it will handle
180
+ // printing the : on its own since it could change sides.
181
+ const parentNode = path.getParentNode();
182
+ if (parentNode.type !== "assoc_new" || parentNode.body[0] !== node) {
183
+ parts.unshift(":");
184
+ }
90
185
 
91
- return concat([":", quote].concat(path.map(print, "body")).concat(quote));
186
+ return concat(parts);
92
187
  }
93
188
 
94
189
  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
@@ -617,19 +645,19 @@ class Prettier::Parser < Ripper
617
645
  # bodystmt can't actually determine its bounds appropriately because it
618
646
  # doesn't necessarily know where it started. So the parent node needs to
619
647
  # report back down into this one where it goes.
620
- class BodyStmt < SimpleDelegator
648
+ class BodyStmt < Node
621
649
  def bind(sc, ec)
622
- merge!(sc: sc, ec: ec)
623
- parts = self[:body]
650
+ value.merge!(sc: sc, ec: ec)
651
+ parts = value[:body]
624
652
 
625
653
  # Here we're going to determine the bounds for the stmts
626
654
  consequent = parts[1..-1].compact.first
627
- self[:body][0].bind(sc, consequent ? consequent[:sc] : ec)
655
+ value[:body][0].bind(sc, consequent ? consequent[:sc] : ec)
628
656
 
629
657
  # Next we're going to determine the rescue clause if there is one
630
658
  if parts[1]
631
659
  consequent = parts[2..-1].compact.first
632
- self[:body][1].bind_end(consequent ? consequent[:sc] : ec)
660
+ value[:body][1].bind_end(consequent ? consequent[:sc] : ec)
633
661
  end
634
662
  end
635
663
  end
@@ -638,6 +666,7 @@ class Prettier::Parser < Ripper
638
666
  # of clauses within the body of a method or block.
639
667
  def on_bodystmt(stmts, rescued, ensured, elsed)
640
668
  BodyStmt.new(
669
+ self,
641
670
  type: :bodystmt,
642
671
  body: [stmts, rescued, ensured, elsed],
643
672
  sl: lineno,
@@ -662,7 +691,7 @@ class Prettier::Parser < Ripper
662
691
  body: [block_var, stmts],
663
692
  sl: beging[:sl],
664
693
  sc: beging[:sc],
665
- el: ending[:el],
694
+ el: [ending[:el], stmts[:el]].max,
666
695
  ec: ending[:ec]
667
696
  }
668
697
  end
@@ -715,7 +744,7 @@ class Prettier::Parser < Ripper
715
744
  body: [receiver, oper, sending],
716
745
  sl: receiver[:sl],
717
746
  sc: receiver[:sc],
718
- el: ending[:el],
747
+ el: [ending[:el], receiver[:el]].max,
719
748
  ec: ending[:ec]
720
749
  }
721
750
  end
@@ -1063,7 +1092,7 @@ class Prettier::Parser < Ripper
1063
1092
 
1064
1093
  beging.merge(
1065
1094
  type: :dyna_symbol,
1066
- quote: beging[:body][1],
1095
+ quote: beging[:body],
1067
1096
  body: string[:body],
1068
1097
  el: ending[:el],
1069
1098
  ec: ending[:ec]
@@ -1729,6 +1758,28 @@ class Prettier::Parser < Ripper
1729
1758
  )
1730
1759
  end
1731
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
+
1732
1783
  # The program node is the very top of the AST. Here we'll attach all of
1733
1784
  # the comments that we've gathered up over the course of parsing the
1734
1785
  # source string. We'll also attach on the __END__ content if there was
@@ -1823,12 +1874,12 @@ class Prettier::Parser < Ripper
1823
1874
  # doesn't really have all of the information that it needs in order to
1824
1875
  # determine its ending. Therefore it relies on its parent bodystmt node to
1825
1876
  # report its ending to it.
1826
- class Rescue < SimpleDelegator
1877
+ class Rescue < Node
1827
1878
  def bind_end(ec)
1828
- merge!(ec: ec)
1879
+ value.merge!(ec: ec)
1829
1880
 
1830
- stmts = self[:body][1]
1831
- consequent = self[:body][2]
1881
+ stmts = value[:body][1]
1882
+ consequent = value[:body][2]
1832
1883
 
1833
1884
  if consequent
1834
1885
  consequent.bind_end(ec)
@@ -1864,6 +1915,7 @@ class Prettier::Parser < Ripper
1864
1915
  end
1865
1916
 
1866
1917
  Rescue.new(
1918
+ self,
1867
1919
  beging.merge!(
1868
1920
  type: :rescue,
1869
1921
  body: [rescue_ex, stmts, consequent],
@@ -1964,36 +2016,29 @@ class Prettier::Parser < Ripper
1964
2016
  # stmts nodes will report back down the location information. We then
1965
2017
  # propagate that onto void_stmt nodes inside the stmts in order to make sure
1966
2018
  # all comments get printed appropriately.
1967
- class Stmts < SimpleDelegator
1968
- attr_reader :parser
1969
-
1970
- def initialize(parser, values)
1971
- @parser = parser
1972
- __setobj__(values)
1973
- end
1974
-
2019
+ class Stmts < Node
1975
2020
  def bind(sc, ec)
1976
- merge!(sc: sc, ec: ec)
2021
+ value.merge!(sc: sc, ec: ec)
1977
2022
 
1978
- if self[:body][0][:type] == :void_stmt
1979
- 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)
1980
2025
  end
1981
2026
 
1982
2027
  attach_comments(sc, ec)
1983
2028
  end
1984
2029
 
1985
2030
  def bind_end(ec)
1986
- merge!(ec: ec)
2031
+ value.merge!(ec: ec)
1987
2032
  end
1988
2033
 
1989
2034
  def <<(statement)
1990
- if self[:body].any?
1991
- merge!(statement.slice(:el, :ec))
2035
+ if value[:body].any?
2036
+ value.merge!(statement.slice(:el, :ec))
1992
2037
  else
1993
- merge!(statement.slice(:sl, :el, :sc, :ec))
2038
+ value.merge!(statement.slice(:sl, :el, :sc, :ec))
1994
2039
  end
1995
2040
 
1996
- self[:body] << statement
2041
+ value[:body] << statement
1997
2042
  self
1998
2043
  end
1999
2044
 
@@ -2010,7 +2055,7 @@ class Prettier::Parser < Ripper
2010
2055
  return if attachable.empty?
2011
2056
 
2012
2057
  parser.comments -= attachable
2013
- self[:body] = (self[:body] + attachable).sort_by! { |node| node[:sc] }
2058
+ value[:body] = (value[:body] + attachable).sort_by! { |node| node[:sc] }
2014
2059
  end
2015
2060
  end
2016
2061