prettier 0.22.0 → 1.0.0.pre.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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
|