prettier 0.22.0 → 1.0.0.pre.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +63 -7
- data/CONTRIBUTING.md +1 -1
- data/README.md +13 -14
- data/package.json +1 -1
- data/src/embed.js +5 -5
- data/src/nodes/args.js +2 -3
- data/src/nodes/arrays.js +7 -4
- data/src/nodes/calls.js +4 -5
- data/src/nodes/conditionals.js +4 -4
- data/src/nodes/hashes.js +7 -6
- data/src/nodes/heredocs.js +2 -2
- data/src/nodes/hooks.js +5 -3
- data/src/nodes/loops.js +4 -3
- data/src/nodes/methods.js +2 -0
- data/src/nodes/operators.js +24 -13
- data/src/nodes/regexp.js +23 -8
- data/src/nodes/rescue.js +2 -2
- data/src/nodes/statements.js +33 -23
- data/src/nodes/strings.js +11 -10
- data/src/parser.rb +153 -42
- data/src/printer.js +3 -1
- data/src/ruby.js +8 -21
- data/src/toProc.js +1 -1
- data/src/utils.js +13 -0
- metadata +4 -4
data/src/nodes/methods.js
CHANGED
@@ -28,7 +28,9 @@ function printMethod(offset) {
|
|
28
28
|
|
29
29
|
// If the body is empty, we can replace with a ;
|
30
30
|
const stmts = body.body[0].body;
|
31
|
+
|
31
32
|
if (
|
33
|
+
!body.body.slice(1).some((node) => node) &&
|
32
34
|
stmts.length === 1 &&
|
33
35
|
stmts[0].type === "void_stmt" &&
|
34
36
|
!stmts[0].comments
|
data/src/nodes/operators.js
CHANGED
@@ -1,23 +1,34 @@
|
|
1
1
|
const { concat, group, indent, line, softline } = require("../prettier");
|
2
|
+
const { noIndent } = require("../utils");
|
2
3
|
|
3
4
|
function printBinary(path, opts, print) {
|
4
|
-
const operator = path.getValue().body
|
5
|
-
const
|
5
|
+
const [_leftNode, operator, rightNode] = path.getValue().body;
|
6
|
+
const space = operator === "**" ? "" : " ";
|
7
|
+
|
8
|
+
if (noIndent.includes(rightNode.type)) {
|
9
|
+
return group(
|
10
|
+
concat([
|
11
|
+
group(path.call(print, "body", 0)),
|
12
|
+
space,
|
13
|
+
operator,
|
14
|
+
space,
|
15
|
+
group(path.call(print, "body", 2))
|
16
|
+
])
|
17
|
+
);
|
18
|
+
}
|
6
19
|
|
7
20
|
return group(
|
8
21
|
concat([
|
9
22
|
group(path.call(print, "body", 0)),
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
)
|
20
|
-
])
|
23
|
+
space,
|
24
|
+
group(
|
25
|
+
indent(
|
26
|
+
concat([
|
27
|
+
operator,
|
28
|
+
space === "" ? softline : line,
|
29
|
+
path.call(print, "body", 2)
|
30
|
+
])
|
31
|
+
)
|
21
32
|
)
|
22
33
|
])
|
23
34
|
);
|
data/src/nodes/regexp.js
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
const { concat } = require("../prettier");
|
2
2
|
|
3
|
+
function isStringContent(node) {
|
4
|
+
return node.type === "@tstring_content";
|
5
|
+
}
|
6
|
+
|
7
|
+
function shouldUseBraces(node) {
|
8
|
+
const first = node.body[0];
|
9
|
+
|
10
|
+
// If the first part of this regex is plain string content and we have a
|
11
|
+
// space or an =, then we want to use braces because otherwise we could end up
|
12
|
+
// with an ambiguous operator, e.g. foo / bar/ or foo /=bar/
|
13
|
+
if (first && isStringContent(first) && [" ", "="].includes(first.body[0])) {
|
14
|
+
return true;
|
15
|
+
}
|
16
|
+
|
17
|
+
return node.body.some(
|
18
|
+
(child) => isStringContent(child) && child.body.includes("/")
|
19
|
+
);
|
20
|
+
}
|
21
|
+
|
3
22
|
// This function is responsible for printing out regexp_literal nodes. They can
|
4
23
|
// either use the special %r literal syntax or they can use forward slashes. At
|
5
24
|
// the end of either of those they can have modifiers like m or x that have
|
@@ -8,16 +27,12 @@ const { concat } = require("../prettier");
|
|
8
27
|
// We favor the use of forward slashes unless the regex contains a forward slash
|
9
28
|
// itself. In that case we switch over to using %r with braces.
|
10
29
|
function printRegexpLiteral(path, opts, print) {
|
11
|
-
const
|
12
|
-
const
|
13
|
-
|
14
|
-
const useBraces = contents.some(
|
15
|
-
(content) => typeof content === "string" && content.includes("/")
|
16
|
-
);
|
30
|
+
const node = path.getValue();
|
31
|
+
const useBraces = shouldUseBraces(node);
|
17
32
|
|
18
33
|
const parts = [useBraces ? "%r{" : "/"]
|
19
|
-
.concat(
|
20
|
-
.concat([useBraces ? "}" : "/", ending.slice(1)]);
|
34
|
+
.concat(path.map(print, "body"))
|
35
|
+
.concat([useBraces ? "}" : "/", node.ending.slice(1)]);
|
21
36
|
|
22
37
|
return concat(parts);
|
23
38
|
}
|
data/src/nodes/rescue.js
CHANGED
@@ -20,8 +20,8 @@ function printBegin(path, opts, print) {
|
|
20
20
|
|
21
21
|
function printEnsure(path, opts, print) {
|
22
22
|
return concat([
|
23
|
-
"
|
24
|
-
indent(concat([hardline,
|
23
|
+
path.call(print, "body", 0),
|
24
|
+
indent(concat([hardline, path.call(print, "body", 1)]))
|
25
25
|
]);
|
26
26
|
}
|
27
27
|
|
data/src/nodes/statements.js
CHANGED
@@ -12,35 +12,45 @@ const {
|
|
12
12
|
trim
|
13
13
|
} = require("../prettier");
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
function printBodyStmt(path, opts, print) {
|
16
|
+
const [stmts, rescue, elseClause, ensure] = path.getValue().body;
|
17
|
+
const parts = [];
|
18
|
+
|
19
|
+
if (
|
20
|
+
stmts.body.length > 1 ||
|
21
|
+
stmts.body[0].type != "void_stmt" ||
|
22
|
+
stmts.body[0].comments
|
23
|
+
) {
|
24
|
+
parts.push(path.call(print, "body", 0));
|
25
|
+
}
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
if (rescue) {
|
28
|
+
parts.push(dedent(concat([hardline, path.call(print, "body", 1)])));
|
29
|
+
}
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
if (elseClause) {
|
32
|
+
// Before Ruby 2.6, this piece of bodystmt was an explicit "else" node
|
33
|
+
const stmts =
|
34
|
+
elseClause.type === "else"
|
35
|
+
? path.call(print, "body", 2, "body", 0)
|
36
|
+
: path.call(print, "body", 2);
|
34
37
|
|
35
|
-
|
36
|
-
|
38
|
+
parts.push(concat([dedent(concat([hardline, "else"])), hardline, stmts]));
|
39
|
+
}
|
37
40
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
if (ensure) {
|
42
|
+
parts.push(dedent(concat([hardline, path.call(print, "body", 3)])));
|
43
|
+
}
|
44
|
+
|
45
|
+
return group(concat(parts));
|
46
|
+
}
|
41
47
|
|
42
|
-
|
48
|
+
module.exports = {
|
49
|
+
"@__end__": (path, _opts, _print) => {
|
50
|
+
const { body } = path.getValue();
|
51
|
+
return concat([trim, "__END__", literalline, body]);
|
43
52
|
},
|
53
|
+
bodystmt: printBodyStmt,
|
44
54
|
paren: (path, opts, print) => {
|
45
55
|
if (!path.getValue().body[0]) {
|
46
56
|
return "()";
|
data/src/nodes/strings.js
CHANGED
@@ -66,7 +66,7 @@ function getClosingQuote(quote) {
|
|
66
66
|
return quote;
|
67
67
|
}
|
68
68
|
|
69
|
-
const boundary = /%
|
69
|
+
const boundary = /%[Qq]?(.)/.exec(quote)[1];
|
70
70
|
if (boundary in quotePairs) {
|
71
71
|
return quotePairs[boundary];
|
72
72
|
}
|
@@ -77,14 +77,14 @@ function getClosingQuote(quote) {
|
|
77
77
|
// Prints a @CHAR node. @CHAR nodes are special character strings that usually
|
78
78
|
// are strings of length 1. If they're any longer than we'll try to apply the
|
79
79
|
// correct quotes.
|
80
|
-
function printChar(path, {
|
80
|
+
function printChar(path, { rubySingleQuote }, _print) {
|
81
81
|
const { body } = path.getValue();
|
82
82
|
|
83
83
|
if (body.length !== 2) {
|
84
84
|
return body;
|
85
85
|
}
|
86
86
|
|
87
|
-
const quote =
|
87
|
+
const quote = rubySingleQuote ? "'" : '"';
|
88
88
|
return concat([quote, body.slice(1), quote]);
|
89
89
|
}
|
90
90
|
|
@@ -107,13 +107,13 @@ function printStringDVar(path, opts, print) {
|
|
107
107
|
// wishes of the user with regards to single versus double quotes, but if the
|
108
108
|
// string contains any escape expressions then it will just keep the original
|
109
109
|
// quotes.
|
110
|
-
function printStringLiteral(path, {
|
110
|
+
function printStringLiteral(path, { rubySingleQuote }, print) {
|
111
111
|
const node = path.getValue();
|
112
112
|
|
113
113
|
// If the string is empty, it will not have any parts, so just print out the
|
114
114
|
// quotes corresponding to the config
|
115
115
|
if (node.body.length === 0) {
|
116
|
-
return
|
116
|
+
return rubySingleQuote ? "''" : '""';
|
117
117
|
}
|
118
118
|
|
119
119
|
// Determine the quote that should enclose the new string
|
@@ -121,7 +121,7 @@ function printStringLiteral(path, { preferSingleQuotes }, print) {
|
|
121
121
|
if (isQuoteLocked(node)) {
|
122
122
|
quote = node.quote;
|
123
123
|
} else {
|
124
|
-
quote =
|
124
|
+
quote = rubySingleQuote && isSingleQuotable(node) ? "'" : '"';
|
125
125
|
}
|
126
126
|
|
127
127
|
const parts = node.body.map((part, index) => {
|
@@ -167,10 +167,11 @@ module.exports = {
|
|
167
167
|
string_embexpr: (path, opts, print) => {
|
168
168
|
const parts = path.call(print, "body", 0);
|
169
169
|
|
170
|
-
// If the interpolated expression is inside of
|
171
|
-
// that gets sent to the command line) then we don't want
|
172
|
-
// indent, as this can lead to some very odd looking
|
173
|
-
|
170
|
+
// If the interpolated expression is inside of a heredoc or an xstring
|
171
|
+
// literal (a string that gets sent to the command line) then we don't want
|
172
|
+
// to automatically indent, as this can lead to some very odd looking
|
173
|
+
// expressions
|
174
|
+
if (["heredoc", "xstring_literal"].includes(path.getParentNode().type)) {
|
174
175
|
return concat(["#{", parts, "}"]);
|
175
176
|
}
|
176
177
|
|
data/src/parser.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# We implement our own version checking here instead of using Gem::Version so
|
4
4
|
# that we can use the --disable-gems flag.
|
5
|
-
RUBY_MAJOR, RUBY_MINOR, * = RUBY_VERSION.split('.').map(&:to_i)
|
5
|
+
RUBY_MAJOR, RUBY_MINOR, RUBY_PATCH, * = RUBY_VERSION.split('.').map(&:to_i)
|
6
6
|
|
7
7
|
if (RUBY_MAJOR < 2) || ((RUBY_MAJOR == 2) && (RUBY_MINOR < 5))
|
8
8
|
warn(
|
@@ -115,15 +115,14 @@ class Prettier::Parser < Ripper
|
|
115
115
|
# This will break everything, so we need to force the encoding back into
|
116
116
|
# UTF-8 so that the JSON library won't break.
|
117
117
|
def on_comment(value)
|
118
|
-
@comments <<
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
}
|
118
|
+
@comments << {
|
119
|
+
type: :@comment,
|
120
|
+
value: value[1..-1].chomp.force_encoding('UTF-8'),
|
121
|
+
start: lineno,
|
122
|
+
end: lineno,
|
123
|
+
char_start: char_pos,
|
124
|
+
char_end: char_pos + value.length - 1
|
125
|
+
}
|
127
126
|
end
|
128
127
|
|
129
128
|
# ignored_nl is a special kind of scanner event that passes nil as the value,
|
@@ -187,11 +186,14 @@ class Prettier::Parser < Ripper
|
|
187
186
|
beging = find_scanner_event(:@lbrace)
|
188
187
|
ending = find_scanner_event(:@rbrace)
|
189
188
|
|
190
|
-
stmts.bind(
|
189
|
+
stmts.bind(
|
190
|
+
find_next_statement_start(beging[:char_end]),
|
191
|
+
ending[:char_start]
|
192
|
+
)
|
191
193
|
|
192
194
|
find_scanner_event(:@kw, 'BEGIN').merge!(
|
193
195
|
type: :BEGIN,
|
194
|
-
body: [stmts],
|
196
|
+
body: [beging, stmts],
|
195
197
|
end: ending[:end],
|
196
198
|
char_end: ending[:char_end]
|
197
199
|
)
|
@@ -211,10 +213,16 @@ class Prettier::Parser < Ripper
|
|
211
213
|
beging = find_scanner_event(:@lbrace)
|
212
214
|
ending = find_scanner_event(:@rbrace)
|
213
215
|
|
214
|
-
stmts.bind(
|
216
|
+
stmts.bind(
|
217
|
+
find_next_statement_start(beging[:char_end]),
|
218
|
+
ending[:char_start]
|
219
|
+
)
|
215
220
|
|
216
221
|
find_scanner_event(:@kw, 'END').merge!(
|
217
|
-
type: :END,
|
222
|
+
type: :END,
|
223
|
+
body: [beging, stmts],
|
224
|
+
end: ending[:end],
|
225
|
+
char_end: ending[:char_end]
|
218
226
|
)
|
219
227
|
end
|
220
228
|
|
@@ -352,7 +360,12 @@ class Prettier::Parser < Ripper
|
|
352
360
|
# method inside a set of parentheses.
|
353
361
|
def on_arg_paren(args)
|
354
362
|
beging = find_scanner_event(:@lparen)
|
355
|
-
|
363
|
+
rparen = find_scanner_event(:@rparen)
|
364
|
+
|
365
|
+
# If the arguments exceed the ending of the parentheses, then we know we
|
366
|
+
# have a heredoc in the arguments, and we need to use the bounds of the
|
367
|
+
# arguments to determine how large the arg_paren is.
|
368
|
+
ending = (args && args[:end] > rparen[:end]) ? args : rparen
|
356
369
|
|
357
370
|
{
|
358
371
|
type: :arg_paren,
|
@@ -559,7 +572,7 @@ class Prettier::Parser < Ripper
|
|
559
572
|
# Next we're going to determine the rescue clause if there is one
|
560
573
|
if parts[1]
|
561
574
|
consequent = parts[2..-1].compact.first
|
562
|
-
self[:body][1].
|
575
|
+
self[:body][1].bind_end(consequent ? consequent[:char_start] : char_end)
|
563
576
|
end
|
564
577
|
end
|
565
578
|
end
|
@@ -601,7 +614,16 @@ class Prettier::Parser < Ripper
|
|
601
614
|
# accepts as an argument an args or args_add_block event that contains all
|
602
615
|
# of the arguments being passed to the break.
|
603
616
|
def on_break(args_add_block)
|
604
|
-
find_scanner_event(:@kw, 'break')
|
617
|
+
beging = find_scanner_event(:@kw, 'break')
|
618
|
+
|
619
|
+
# You can hit this if you are passing no arguments to break but it has a
|
620
|
+
# comment right after it. In that case we can just use the location
|
621
|
+
# information straight from the keyword.
|
622
|
+
if args_add_block[:type] == :args
|
623
|
+
return beging.merge!(type: :break, body: [args_add_block])
|
624
|
+
end
|
625
|
+
|
626
|
+
beging.merge!(
|
605
627
|
type: :break,
|
606
628
|
body: [args_add_block],
|
607
629
|
end: args_add_block[:end],
|
@@ -621,6 +643,10 @@ class Prettier::Parser < Ripper
|
|
621
643
|
# foo.(1, 2, 3)
|
622
644
|
#
|
623
645
|
def on_call(receiver, oper, sending)
|
646
|
+
# Make sure we take the operator out of the scanner events so that it
|
647
|
+
# doesn't get confused for a unary operator later.
|
648
|
+
scanner_events.delete(oper)
|
649
|
+
|
624
650
|
ending = sending
|
625
651
|
|
626
652
|
if sending == :call
|
@@ -653,6 +679,27 @@ class Prettier::Parser < Ripper
|
|
653
679
|
)
|
654
680
|
end
|
655
681
|
|
682
|
+
# Finds the next position in the source string that begins a statement. This
|
683
|
+
# is used to bind statements lists and make sure they don't include a
|
684
|
+
# preceding comment. For example, we want the following comment to be attached
|
685
|
+
# to the class node and not the statement node:
|
686
|
+
#
|
687
|
+
# class Foo # :nodoc:
|
688
|
+
# ...
|
689
|
+
# end
|
690
|
+
#
|
691
|
+
# By finding the next non-space character, we can make sure that the bounds of
|
692
|
+
# the statement list are correct.
|
693
|
+
def find_next_statement_start(position)
|
694
|
+
remaining = source[position..-1]
|
695
|
+
|
696
|
+
if remaining.sub(/\A +/, '')[0] == '#'
|
697
|
+
return position + remaining.index("\n")
|
698
|
+
end
|
699
|
+
|
700
|
+
position
|
701
|
+
end
|
702
|
+
|
656
703
|
# class is a parser event that represents defining a class. It accepts as
|
657
704
|
# arguments the name of the class, the optional name of the superclass,
|
658
705
|
# and the bodystmt event that represents the statements evaluated within
|
@@ -661,7 +708,10 @@ class Prettier::Parser < Ripper
|
|
661
708
|
beging = find_scanner_event(:@kw, 'class')
|
662
709
|
ending = find_scanner_event(:@kw, 'end')
|
663
710
|
|
664
|
-
bodystmt.bind(
|
711
|
+
bodystmt.bind(
|
712
|
+
find_next_statement_start((superclass || const)[:char_end]),
|
713
|
+
ending[:char_start]
|
714
|
+
)
|
665
715
|
|
666
716
|
{
|
667
717
|
type: :class,
|
@@ -761,6 +811,11 @@ class Prettier::Parser < Ripper
|
|
761
811
|
# └> ident
|
762
812
|
#
|
763
813
|
def on_def(ident, params, bodystmt)
|
814
|
+
# Make sure to delete this scanner event in case you're defining something
|
815
|
+
# like def class which would lead to this being a kw and causing all kinds
|
816
|
+
# of trouble
|
817
|
+
scanner_events.delete(ident)
|
818
|
+
|
764
819
|
if params[:type] == :params && !params[:body].any?
|
765
820
|
location = ident[:char_end]
|
766
821
|
params.merge!(char_start: location, char_end: location)
|
@@ -769,7 +824,10 @@ class Prettier::Parser < Ripper
|
|
769
824
|
beging = find_scanner_event(:@kw, 'def')
|
770
825
|
ending = find_scanner_event(:@kw, 'end')
|
771
826
|
|
772
|
-
bodystmt.bind(
|
827
|
+
bodystmt.bind(
|
828
|
+
find_next_statement_start(params[:char_end]),
|
829
|
+
ending[:char_start]
|
830
|
+
)
|
773
831
|
|
774
832
|
{
|
775
833
|
type: :def,
|
@@ -796,6 +854,11 @@ class Prettier::Parser < Ripper
|
|
796
854
|
# └> target
|
797
855
|
#
|
798
856
|
def on_defs(target, oper, ident, params, bodystmt)
|
857
|
+
# Make sure to delete this scanner event in case you're defining something
|
858
|
+
# like def class which would lead to this being a kw and causing all kinds
|
859
|
+
# of trouble
|
860
|
+
scanner_events.delete(ident)
|
861
|
+
|
799
862
|
if params[:type] == :params && !params[:body].any?
|
800
863
|
location = ident[:char_end]
|
801
864
|
params.merge!(char_start: location, char_end: location)
|
@@ -804,7 +867,10 @@ class Prettier::Parser < Ripper
|
|
804
867
|
beging = find_scanner_event(:@kw, 'def')
|
805
868
|
ending = find_scanner_event(:@kw, 'end')
|
806
869
|
|
807
|
-
bodystmt.bind(
|
870
|
+
bodystmt.bind(
|
871
|
+
find_next_statement_start(params[:char_end]),
|
872
|
+
ending[:char_start]
|
873
|
+
)
|
808
874
|
|
809
875
|
{
|
810
876
|
type: :defs,
|
@@ -1029,13 +1095,23 @@ class Prettier::Parser < Ripper
|
|
1029
1095
|
# and its subsequent statements.
|
1030
1096
|
def on_ensure(stmts)
|
1031
1097
|
beging = find_scanner_event(:@kw, 'ensure')
|
1032
|
-
ending = find_scanner_event(:@kw, 'end')
|
1033
1098
|
|
1034
|
-
|
1099
|
+
# Specifically not using find_scanner_event here because we don't want to
|
1100
|
+
# consume the :@end event, because that would break def..ensure..end chains.
|
1101
|
+
index =
|
1102
|
+
scanner_events.rindex do |scanner_event|
|
1103
|
+
scanner_event[:type] == :@kw && scanner_event[:body] == 'end'
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
ending = scanner_events[index]
|
1107
|
+
stmts.bind(
|
1108
|
+
find_next_statement_start(beging[:char_end]),
|
1109
|
+
ending[:char_start]
|
1110
|
+
)
|
1035
1111
|
|
1036
1112
|
{
|
1037
1113
|
type: :ensure,
|
1038
|
-
body: [stmts],
|
1114
|
+
body: [beging, stmts],
|
1039
1115
|
start: beging[:start],
|
1040
1116
|
char_start: beging[:char_start],
|
1041
1117
|
end: ending[:end],
|
@@ -1126,21 +1202,25 @@ class Prettier::Parser < Ripper
|
|
1126
1202
|
# prettier parser, we'll later attempt to print it using that parser and
|
1127
1203
|
# printer through our embed function.
|
1128
1204
|
def on_heredoc_beg(beging)
|
1129
|
-
{
|
1130
|
-
type: :heredoc,
|
1131
|
-
beging: beging,
|
1205
|
+
location = {
|
1132
1206
|
start: lineno,
|
1133
1207
|
end: lineno,
|
1134
|
-
char_start: char_pos
|
1135
|
-
char_end: char_pos
|
1136
|
-
}
|
1208
|
+
char_start: char_pos,
|
1209
|
+
char_end: char_pos + beging.length + 1
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
# Here we're going to artificially create an extra node type so that if
|
1213
|
+
# there are comments after the declaration of a heredoc, they get printed.
|
1214
|
+
location.merge(
|
1215
|
+
type: :heredoc, beging: location.merge(type: :@heredoc_beg, body: beging)
|
1216
|
+
).tap { |node| @heredocs << node }
|
1137
1217
|
end
|
1138
1218
|
|
1139
1219
|
# This is a parser event that occurs when you're using a heredoc with a
|
1140
1220
|
# tilde. These are considered `heredoc_dedent` nodes, whereas the hyphen
|
1141
1221
|
# heredocs show up as string literals.
|
1142
1222
|
def on_heredoc_dedent(string, _width)
|
1143
|
-
@heredocs[-1].merge!(string
|
1223
|
+
@heredocs[-1].merge!(body: string[:body])
|
1144
1224
|
end
|
1145
1225
|
|
1146
1226
|
# This is a scanner event that represents the end of the heredoc.
|
@@ -1306,6 +1386,14 @@ class Prettier::Parser < Ripper
|
|
1306
1386
|
# arguments and parentheses. It accepts as arguments the method being called
|
1307
1387
|
# and the arg_paren event that contains the arguments to the method.
|
1308
1388
|
def on_method_add_arg(fcall, arg_paren)
|
1389
|
+
# You can hit this if you are passing no arguments to a method that ends in
|
1390
|
+
# a question mark. Because it knows it has to be a method and not a local
|
1391
|
+
# variable. In that case we can just use the location information straight
|
1392
|
+
# from the fcall.
|
1393
|
+
if arg_paren[:type] == :args
|
1394
|
+
return fcall.merge(type: :method_add_arg, body: [fcall, arg_paren])
|
1395
|
+
end
|
1396
|
+
|
1309
1397
|
{
|
1310
1398
|
type: :method_add_arg,
|
1311
1399
|
body: [fcall, arg_paren],
|
@@ -1418,7 +1506,10 @@ class Prettier::Parser < Ripper
|
|
1418
1506
|
beging = find_scanner_event(:@kw, 'module')
|
1419
1507
|
ending = find_scanner_event(:@kw, 'end')
|
1420
1508
|
|
1421
|
-
bodystmt.bind(
|
1509
|
+
bodystmt.bind(
|
1510
|
+
find_next_statement_start(const[:char_end]),
|
1511
|
+
ending[:char_start]
|
1512
|
+
)
|
1422
1513
|
|
1423
1514
|
{
|
1424
1515
|
type: :module,
|
@@ -1643,17 +1734,17 @@ class Prettier::Parser < Ripper
|
|
1643
1734
|
# determine its ending. Therefore it relies on its parent bodystmt node to
|
1644
1735
|
# report its ending to it.
|
1645
1736
|
class Rescue < SimpleDelegator
|
1646
|
-
def
|
1737
|
+
def bind_end(char_end)
|
1647
1738
|
merge!(char_end: char_end)
|
1648
1739
|
|
1649
1740
|
stmts = self[:body][2]
|
1650
1741
|
consequent = self[:body][3]
|
1651
1742
|
|
1652
1743
|
if consequent
|
1653
|
-
consequent.
|
1654
|
-
stmts.
|
1744
|
+
consequent.bind_end(char_end)
|
1745
|
+
stmts.bind_end(consequent[:char_start])
|
1655
1746
|
else
|
1656
|
-
stmts.
|
1747
|
+
stmts.bind_end(char_end)
|
1657
1748
|
end
|
1658
1749
|
end
|
1659
1750
|
end
|
@@ -1663,10 +1754,10 @@ class Prettier::Parser < Ripper
|
|
1663
1754
|
def on_rescue(exceptions, variable, stmts, consequent)
|
1664
1755
|
beging = find_scanner_event(:@kw, 'rescue')
|
1665
1756
|
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
)
|
1757
|
+
last_exception = exceptions.is_a?(Array) ? exceptions[-1] : exceptions
|
1758
|
+
last_node = variable || last_exception || beging
|
1759
|
+
|
1760
|
+
stmts.bind(find_next_statement_start(last_node[:char_end]), char_pos)
|
1670
1761
|
|
1671
1762
|
Rescue.new(
|
1672
1763
|
beging.merge!(
|
@@ -1750,7 +1841,10 @@ class Prettier::Parser < Ripper
|
|
1750
1841
|
beging = find_scanner_event(:@kw, 'class')
|
1751
1842
|
ending = find_scanner_event(:@kw, 'end')
|
1752
1843
|
|
1753
|
-
bodystmt.bind(
|
1844
|
+
bodystmt.bind(
|
1845
|
+
find_next_statement_start(target[:char_end]),
|
1846
|
+
ending[:char_start]
|
1847
|
+
)
|
1754
1848
|
|
1755
1849
|
{
|
1756
1850
|
type: :sclass,
|
@@ -1778,6 +1872,10 @@ class Prettier::Parser < Ripper
|
|
1778
1872
|
end
|
1779
1873
|
end
|
1780
1874
|
|
1875
|
+
def bind_end(char_end)
|
1876
|
+
merge!(char_end: char_end)
|
1877
|
+
end
|
1878
|
+
|
1781
1879
|
def <<(statement)
|
1782
1880
|
if self[:body].any?
|
1783
1881
|
merge!(statement.slice(:end, :char_end))
|
@@ -1948,7 +2046,7 @@ class Prettier::Parser < Ripper
|
|
1948
2046
|
# symbol node (for most cases) or an ident node (in the case that we're
|
1949
2047
|
# using bare words, as in an alias node like alias foo bar).
|
1950
2048
|
def on_symbol_literal(contents)
|
1951
|
-
if
|
2049
|
+
if scanner_events[-1] == contents
|
1952
2050
|
contents.merge(type: :symbol_literal, body: [contents])
|
1953
2051
|
else
|
1954
2052
|
beging = find_scanner_event(:@symbeg)
|
@@ -2042,7 +2140,18 @@ class Prettier::Parser < Ripper
|
|
2042
2140
|
paren: paren
|
2043
2141
|
)
|
2044
2142
|
else
|
2045
|
-
find_scanner_event
|
2143
|
+
# Special case instead of using find_scanner_event here. It turns out that
|
2144
|
+
# if you have a range that goes from a negative number to a negative
|
2145
|
+
# number then you can end up with a .. or a ... that's higher in the
|
2146
|
+
# stack. So we need to explicitly disallow those operators.
|
2147
|
+
index =
|
2148
|
+
scanner_events.rindex do |scanner_event|
|
2149
|
+
scanner_event[:type] == :@op &&
|
2150
|
+
!%w[.. ...].include?(scanner_event[:body])
|
2151
|
+
end
|
2152
|
+
|
2153
|
+
beging = scanner_events.delete_at(index)
|
2154
|
+
beging.merge!(
|
2046
2155
|
type: :unary,
|
2047
2156
|
oper: oper[0],
|
2048
2157
|
body: [value],
|
@@ -2335,6 +2444,8 @@ class Prettier::Parser < Ripper
|
|
2335
2444
|
|
2336
2445
|
if heredoc && heredoc[:beging][3] = '`'
|
2337
2446
|
heredoc.merge(type: :xstring, body: [])
|
2447
|
+
elsif RUBY_MAJOR <= 2 && RUBY_MINOR <= 5 && RUBY_PATCH < 7
|
2448
|
+
{ type: :xstring, body: [] }
|
2338
2449
|
else
|
2339
2450
|
find_scanner_event(:@backtick).merge!(type: :xstring, body: [])
|
2340
2451
|
end
|