prettier 1.5.2 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
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