prettier 1.2.4 → 1.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +351 -361
- data/README.md +11 -96
- data/node_modules/prettier/index.js +54 -54
- data/package.json +1 -2
- data/src/haml/embed.js +87 -0
- data/src/haml/nodes/comment.js +27 -0
- data/src/haml/nodes/doctype.js +34 -0
- data/src/haml/nodes/filter.js +16 -0
- data/src/haml/nodes/hamlComment.js +21 -0
- data/src/haml/nodes/plain.js +6 -0
- data/src/haml/nodes/root.js +8 -0
- data/src/haml/nodes/script.js +33 -0
- data/src/haml/nodes/silentScript.js +59 -0
- data/src/haml/nodes/tag.js +193 -0
- data/src/haml/parser.js +22 -0
- data/src/haml/parser.rb +138 -0
- data/src/haml/printer.js +28 -0
- data/src/parser/getLang.js +32 -0
- data/src/parser/getNetcat.js +50 -0
- data/src/parser/netcat.js +15 -0
- data/src/parser/parseSync.js +33 -0
- data/src/parser/requestParse.js +74 -0
- data/src/parser/server.rb +61 -0
- data/src/plugin.js +26 -4
- data/src/rbs/parser.js +39 -0
- data/src/rbs/parser.rb +94 -0
- data/src/rbs/printer.js +605 -0
- data/src/ruby/embed.js +54 -8
- data/src/ruby/nodes/args.js +20 -6
- data/src/ruby/nodes/arrays.js +36 -33
- data/src/ruby/nodes/calls.js +12 -43
- data/src/ruby/nodes/class.js +17 -27
- data/src/ruby/nodes/commands.js +8 -3
- data/src/ruby/nodes/conditionals.js +1 -1
- data/src/ruby/nodes/hashes.js +28 -14
- data/src/ruby/nodes/loops.js +4 -10
- data/src/ruby/nodes/methods.js +4 -11
- data/src/ruby/nodes/rescue.js +32 -25
- data/src/ruby/nodes/statements.js +6 -5
- data/src/ruby/nodes/strings.js +7 -6
- data/src/ruby/parser.js +2 -50
- data/src/ruby/parser.rb +113 -43
- data/src/ruby/printer.js +8 -5
- data/src/utils.js +1 -0
- data/src/utils/inlineEnsureParens.js +8 -1
- data/src/utils/isEmptyBodyStmt.js +7 -0
- data/src/utils/isEmptyStmts.js +9 -5
- data/src/utils/noIndent.js +1 -0
- data/src/utils/printEmptyCollection.js +9 -2
- metadata +25 -2
@@ -219,7 +219,7 @@ const printConditional = (keyword) => (path, { rubyModifier }, print) => {
|
|
219
219
|
|
220
220
|
// If the body of the conditional is empty, then we explicitly have to use the
|
221
221
|
// block form.
|
222
|
-
if (isEmptyStmts(statements)
|
222
|
+
if (isEmptyStmts(statements)) {
|
223
223
|
return concat([
|
224
224
|
`${keyword} `,
|
225
225
|
align(keyword.length + 1, path.call(print, "body", 0)),
|
data/src/ruby/nodes/hashes.js
CHANGED
@@ -6,6 +6,7 @@ const {
|
|
6
6
|
join,
|
7
7
|
line
|
8
8
|
} = require("../../prettier");
|
9
|
+
|
9
10
|
const {
|
10
11
|
getTrailingComma,
|
11
12
|
printEmptyCollection,
|
@@ -89,6 +90,13 @@ function printAssocNew(path, opts, print) {
|
|
89
90
|
const parts = [path.call((keyPath) => keyPrinter(keyPath, print), "body", 0)];
|
90
91
|
const valueDoc = path.call(print, "body", 1);
|
91
92
|
|
93
|
+
// If we're printing a child hash then we want it to break along with its
|
94
|
+
// parent hash, so we don't group the parts.
|
95
|
+
if (valueNode.type === "hash") {
|
96
|
+
parts.push(" ", valueDoc);
|
97
|
+
return concat(parts);
|
98
|
+
}
|
99
|
+
|
92
100
|
if (!skipAssignIndent(valueNode) || keyNode.comments) {
|
93
101
|
parts.push(indent(concat([line, valueDoc])));
|
94
102
|
} else {
|
@@ -125,20 +133,26 @@ function printHash(path, opts, print) {
|
|
125
133
|
return printEmptyCollection(path, opts, "{", "}");
|
126
134
|
}
|
127
135
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
136
|
+
let hashDoc = concat([
|
137
|
+
"{",
|
138
|
+
indent(
|
139
|
+
concat([
|
140
|
+
line,
|
141
|
+
path.call(print, "body", 0),
|
142
|
+
getTrailingComma(opts) ? ifBreak(",", "") : ""
|
143
|
+
])
|
144
|
+
),
|
145
|
+
line,
|
146
|
+
"}"
|
147
|
+
]);
|
148
|
+
|
149
|
+
// If we're inside another hash, then we don't want to group our contents
|
150
|
+
// because we want this hash to break along with its parent hash.
|
151
|
+
if (path.getParentNode().type === "assoc_new") {
|
152
|
+
return hashDoc;
|
153
|
+
}
|
154
|
+
|
155
|
+
return group(hashDoc);
|
142
156
|
}
|
143
157
|
|
144
158
|
module.exports = {
|
data/src/ruby/nodes/loops.js
CHANGED
@@ -10,7 +10,7 @@ const {
|
|
10
10
|
softline
|
11
11
|
} = require("../../prettier");
|
12
12
|
|
13
|
-
const { containsAssignment } = require("../../utils");
|
13
|
+
const { containsAssignment, isEmptyStmts } = require("../../utils");
|
14
14
|
const inlineEnsureParens = require("../../utils/inlineEnsureParens");
|
15
15
|
|
16
16
|
function printLoop(keyword, modifier) {
|
@@ -19,17 +19,11 @@ function printLoop(keyword, modifier) {
|
|
19
19
|
|
20
20
|
// If the only statement inside this while loop is a void statement, then we
|
21
21
|
// can shorten to just displaying the predicate and then a semicolon.
|
22
|
-
if (
|
23
|
-
stmts.body.length === 1 &&
|
24
|
-
stmts.body[0].type === "void_stmt" &&
|
25
|
-
!stmts.body[0].comments
|
26
|
-
) {
|
22
|
+
if (isEmptyStmts(stmts)) {
|
27
23
|
return group(
|
28
24
|
concat([
|
29
|
-
keyword,
|
30
|
-
|
31
|
-
path.call(print, "body", 0),
|
32
|
-
ifBreak(softline, "; "),
|
25
|
+
group(concat([keyword, " ", path.call(print, "body", 0)])),
|
26
|
+
hardline,
|
33
27
|
"end"
|
34
28
|
])
|
35
29
|
);
|
data/src/ruby/nodes/methods.js
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
const { concat, group, hardline, indent, line } = require("../../prettier");
|
2
|
+
const { isEmptyBodyStmt } = require("../../utils");
|
2
3
|
|
3
4
|
function printMethod(offset) {
|
4
5
|
return function printMethodWithOffset(path, opts, print) {
|
5
|
-
const [_name, params,
|
6
|
+
const [_name, params, bodystmt] = path.getValue().body.slice(offset);
|
6
7
|
const declaration = ["def "];
|
7
8
|
|
8
9
|
// In this case, we're printing a method that's defined as a singleton, so
|
@@ -24,16 +25,8 @@ function printMethod(offset) {
|
|
24
25
|
parens ? ")" : ""
|
25
26
|
);
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if (
|
31
|
-
!body.body.slice(1).some((node) => node) &&
|
32
|
-
stmts.length === 1 &&
|
33
|
-
stmts[0].type === "void_stmt" &&
|
34
|
-
!stmts[0].comments
|
35
|
-
) {
|
36
|
-
return group(concat(declaration.concat(["; end"])));
|
28
|
+
if (isEmptyBodyStmt(bodystmt)) {
|
29
|
+
return group(concat(declaration.concat("; end")));
|
37
30
|
}
|
38
31
|
|
39
32
|
return group(
|
data/src/ruby/nodes/rescue.js
CHANGED
@@ -26,28 +26,10 @@ function printEnsure(path, opts, print) {
|
|
26
26
|
}
|
27
27
|
|
28
28
|
function printRescue(path, opts, print) {
|
29
|
-
const [exception, variable, _stmts, addition] = path.getValue().body;
|
30
29
|
const parts = ["rescue"];
|
31
30
|
|
32
|
-
if (
|
33
|
-
|
34
|
-
if (Array.isArray(exception)) {
|
35
|
-
// In this case, it's actually only the one exception (it's an array
|
36
|
-
// of length 1).
|
37
|
-
parts.push(" ", path.call(print, "body", 0, 0));
|
38
|
-
} else {
|
39
|
-
// Here we have multiple exceptions from which we're rescuing, so we
|
40
|
-
// need to align them and join them together.
|
41
|
-
const joiner = concat([",", line]);
|
42
|
-
const exceptions = group(join(joiner, path.call(print, "body", 0)));
|
43
|
-
|
44
|
-
parts.push(" ", align("rescue ".length, exceptions));
|
45
|
-
}
|
46
|
-
}
|
47
|
-
|
48
|
-
if (variable) {
|
49
|
-
parts.push(" => ", path.call(print, "body", 1));
|
50
|
-
}
|
31
|
+
if (path.getValue().body[0]) {
|
32
|
+
parts.push(align("rescue ".length, path.call(print, "body", 0)));
|
51
33
|
} else {
|
52
34
|
// If you don't specify an error to rescue in a `begin/rescue` block, then
|
53
35
|
// implicitly you're rescuing from `StandardError`. In this case, we're
|
@@ -55,16 +37,40 @@ function printRescue(path, opts, print) {
|
|
55
37
|
parts.push(" StandardError");
|
56
38
|
}
|
57
39
|
|
58
|
-
const
|
40
|
+
const bodystmt = path.call(print, "body", 1);
|
59
41
|
|
60
|
-
if (
|
61
|
-
parts.push(indent(concat([hardline,
|
42
|
+
if (bodystmt.parts.length > 0) {
|
43
|
+
parts.push(indent(concat([hardline, bodystmt])));
|
62
44
|
}
|
63
45
|
|
64
46
|
// This is the next clause on the `begin` statement, either another
|
65
47
|
// `rescue`, and `ensure`, or an `else` clause.
|
66
|
-
if (
|
67
|
-
parts.push(concat([hardline, path.call(print, "body",
|
48
|
+
if (path.getValue().body[2]) {
|
49
|
+
parts.push(concat([hardline, path.call(print, "body", 2)]));
|
50
|
+
}
|
51
|
+
|
52
|
+
return group(concat(parts));
|
53
|
+
}
|
54
|
+
|
55
|
+
// This is a container node that we're adding into the AST that isn't present in
|
56
|
+
// Ripper solely so that we have a nice place to attach inline comments.
|
57
|
+
function printRescueEx(path, opts, print) {
|
58
|
+
const [exception, variable] = path.getValue().body;
|
59
|
+
const parts = [];
|
60
|
+
|
61
|
+
if (exception) {
|
62
|
+
let exceptionDoc = path.call(print, "body", 0);
|
63
|
+
|
64
|
+
if (Array.isArray(exceptionDoc)) {
|
65
|
+
const joiner = concat([",", line]);
|
66
|
+
exceptionDoc = group(join(joiner, exceptionDoc));
|
67
|
+
}
|
68
|
+
|
69
|
+
parts.push(" ", exceptionDoc);
|
70
|
+
}
|
71
|
+
|
72
|
+
if (variable) {
|
73
|
+
parts.push(" => ", path.call(print, "body", 1));
|
68
74
|
}
|
69
75
|
|
70
76
|
return group(concat(parts));
|
@@ -89,6 +95,7 @@ module.exports = {
|
|
89
95
|
ensure: printEnsure,
|
90
96
|
redo: literal("redo"),
|
91
97
|
rescue: printRescue,
|
98
|
+
rescue_ex: printRescueEx,
|
92
99
|
rescue_mod: printRescueMod,
|
93
100
|
retry: literal("retry")
|
94
101
|
};
|
@@ -12,15 +12,13 @@ const {
|
|
12
12
|
trim
|
13
13
|
} = require("../../prettier");
|
14
14
|
|
15
|
+
const { isEmptyStmts } = require("../../utils");
|
16
|
+
|
15
17
|
function printBodyStmt(path, opts, print) {
|
16
18
|
const [stmts, rescue, elseClause, ensure] = path.getValue().body;
|
17
19
|
const parts = [];
|
18
20
|
|
19
|
-
if (
|
20
|
-
stmts.body.length > 1 ||
|
21
|
-
stmts.body[0].type != "void_stmt" ||
|
22
|
-
stmts.body[0].comments
|
23
|
-
) {
|
21
|
+
if (!isEmptyStmts(stmts)) {
|
24
22
|
parts.push(path.call(print, "body", 0));
|
25
23
|
}
|
26
24
|
|
@@ -79,6 +77,9 @@ module.exports = {
|
|
79
77
|
const { body } = path.getValue();
|
80
78
|
return concat([trim, "__END__", literalline, body]);
|
81
79
|
},
|
80
|
+
"@comment"(path, opts, _print) {
|
81
|
+
return opts.printer.printComment(path);
|
82
|
+
},
|
82
83
|
bodystmt: printBodyStmt,
|
83
84
|
paren: printParen,
|
84
85
|
program: (path, opts, print) =>
|
data/src/ruby/nodes/strings.js
CHANGED
@@ -4,6 +4,7 @@ const {
|
|
4
4
|
hardline,
|
5
5
|
indent,
|
6
6
|
literalline,
|
7
|
+
removeLines,
|
7
8
|
softline,
|
8
9
|
join
|
9
10
|
} = require("../../prettier");
|
@@ -103,14 +104,14 @@ function printStringDVar(path, opts, print) {
|
|
103
104
|
}
|
104
105
|
|
105
106
|
function printStringEmbExpr(path, opts, print) {
|
107
|
+
const node = path.getValue();
|
106
108
|
const parts = path.call(print, "body", 0);
|
107
109
|
|
108
|
-
// If the
|
109
|
-
//
|
110
|
-
//
|
111
|
-
|
112
|
-
|
113
|
-
return concat(["#{", parts, "}"]);
|
110
|
+
// If the contents of this embedded expression were originally on the same
|
111
|
+
// line in the source, then we're going to leave them in place and assume
|
112
|
+
// that's the way the developer wanted this expression represented.
|
113
|
+
if (node.sl === node.el) {
|
114
|
+
return concat(["#{", removeLines(parts), "}"]);
|
114
115
|
}
|
115
116
|
|
116
117
|
return group(
|
data/src/ruby/parser.js
CHANGED
@@ -1,59 +1,11 @@
|
|
1
|
-
const
|
2
|
-
const path = require("path");
|
3
|
-
|
4
|
-
// In order to properly parse ruby code, we need to tell the ruby process to
|
5
|
-
// parse using UTF-8. Unfortunately, the way that you accomplish this looks
|
6
|
-
// differently depending on your platform.
|
7
|
-
/* istanbul ignore next */
|
8
|
-
const LANG = (() => {
|
9
|
-
const { env, platform } = process;
|
10
|
-
const envValue = env.LC_ALL || env.LC_CTYPE || env.LANG;
|
11
|
-
|
12
|
-
// If an env var is set for the locale that already includes UTF-8 in the
|
13
|
-
// name, then assume we can go with that.
|
14
|
-
if (envValue && envValue.includes("UTF-8")) {
|
15
|
-
return envValue;
|
16
|
-
}
|
17
|
-
|
18
|
-
// Otherwise, we're going to guess which encoding to use based on the system.
|
19
|
-
// This is probably not the best approach in the world, as you could be on
|
20
|
-
// linux and not have C.UTF-8, but in that case you're probably passing an env
|
21
|
-
// var for it. This object below represents all of the possible values of
|
22
|
-
// process.platform per:
|
23
|
-
// https://nodejs.org/api/process.html#process_process_platform
|
24
|
-
return {
|
25
|
-
aix: "C.UTF-8",
|
26
|
-
darwin: "en_US.UTF-8",
|
27
|
-
freebsd: "C.UTF-8",
|
28
|
-
linux: "C.UTF-8",
|
29
|
-
openbsd: "C.UTF-8",
|
30
|
-
sunos: "C.UTF-8",
|
31
|
-
win32: ".UTF-8"
|
32
|
-
}[platform];
|
33
|
-
})();
|
1
|
+
const parseSync = require("../parser/parseSync");
|
34
2
|
|
35
3
|
// This function is responsible for taking an input string of text and returning
|
36
4
|
// to prettier a JavaScript object that is the equivalent AST that represents
|
37
5
|
// the code stored in that string. We accomplish this by spawning a new Ruby
|
38
6
|
// process of parser.rb and reading JSON off STDOUT.
|
39
7
|
function parse(text, _parsers, _opts) {
|
40
|
-
|
41
|
-
"ruby",
|
42
|
-
["--disable-gems", path.join(__dirname, "./parser.rb")],
|
43
|
-
{
|
44
|
-
env: Object.assign({}, process.env, { LANG }),
|
45
|
-
input: text,
|
46
|
-
maxBuffer: 15 * 1024 * 1024 // 15MB
|
47
|
-
}
|
48
|
-
);
|
49
|
-
|
50
|
-
const error = child.stderr.toString();
|
51
|
-
if (error) {
|
52
|
-
throw new Error(error);
|
53
|
-
}
|
54
|
-
|
55
|
-
const response = child.stdout.toString();
|
56
|
-
return JSON.parse(response);
|
8
|
+
return parseSync("ruby", text);
|
57
9
|
}
|
58
10
|
|
59
11
|
const pragmaPattern = /#\s*@(prettier|format)/;
|
data/src/ruby/parser.rb
CHANGED
@@ -14,13 +14,51 @@ if (RUBY_MAJOR < 2) || ((RUBY_MAJOR == 2) && (RUBY_MINOR < 5))
|
|
14
14
|
end
|
15
15
|
|
16
16
|
require 'delegate'
|
17
|
-
require 'json'
|
17
|
+
require 'json'
|
18
18
|
require 'ripper'
|
19
19
|
|
20
|
-
module Prettier
|
20
|
+
module Prettier
|
21
|
+
end
|
21
22
|
|
22
23
|
class Prettier::Parser < Ripper
|
23
|
-
|
24
|
+
# Represents a line in the source. If this class is being used, it means that
|
25
|
+
# every character in the string is 1 byte in length, so we can just return the
|
26
|
+
# start of the line + the index.
|
27
|
+
class SingleByteString
|
28
|
+
def initialize(start)
|
29
|
+
@start = start
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](byteindex)
|
33
|
+
@start + byteindex
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Represents a line in the source. If this class is being used, it means that
|
38
|
+
# there are characters in the string that are multi-byte, so we will build up
|
39
|
+
# an array of indices, such that array[byteindex] will be equal to the index
|
40
|
+
# of the character within the string.
|
41
|
+
class MultiByteString
|
42
|
+
def initialize(start, line)
|
43
|
+
@indices = []
|
44
|
+
|
45
|
+
line
|
46
|
+
.each_char
|
47
|
+
.with_index(start) do |char, index|
|
48
|
+
char.bytesize.times { @indices << index }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def [](byteindex)
|
53
|
+
@indices[byteindex]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :source, :lines, :scanner_events
|
58
|
+
|
59
|
+
# This is an attr_accessor so Stmts objects can grab comments out of this
|
60
|
+
# array and attach them to themselves.
|
61
|
+
attr_accessor :comments
|
24
62
|
|
25
63
|
def initialize(source, *args)
|
26
64
|
super(source, *args)
|
@@ -35,9 +73,30 @@ class Prettier::Parser < Ripper
|
|
35
73
|
@heredocs = []
|
36
74
|
|
37
75
|
@scanner_events = []
|
38
|
-
@line_counts = [
|
76
|
+
@line_counts = []
|
77
|
+
|
78
|
+
# Here we're going to build up a list of SingleByteString or MultiByteString
|
79
|
+
# objects. They're each going to represent a string in the source. They are
|
80
|
+
# used by the `char_pos` method to determine where we are in the source
|
81
|
+
# string.
|
82
|
+
last_index = 0
|
83
|
+
|
84
|
+
@source.lines.each do |line|
|
85
|
+
if line.size == line.bytesize
|
86
|
+
@line_counts << SingleByteString.new(last_index)
|
87
|
+
else
|
88
|
+
@line_counts << MultiByteString.new(last_index, line)
|
89
|
+
end
|
39
90
|
|
40
|
-
|
91
|
+
last_index += line.size
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.parse(source)
|
96
|
+
builder = new(source)
|
97
|
+
|
98
|
+
response = builder.parse
|
99
|
+
response unless builder.error?
|
41
100
|
end
|
42
101
|
|
43
102
|
private
|
@@ -48,7 +107,7 @@ class Prettier::Parser < Ripper
|
|
48
107
|
# this line, then we add the number of columns into this line that we've gone
|
49
108
|
# through.
|
50
109
|
def char_pos
|
51
|
-
line_counts[lineno - 1]
|
110
|
+
@line_counts[lineno - 1][column]
|
52
111
|
end
|
53
112
|
|
54
113
|
# As we build up a list of scanner events, we'll periodically need to go
|
@@ -118,6 +177,7 @@ class Prettier::Parser < Ripper
|
|
118
177
|
@comments << {
|
119
178
|
type: :@comment,
|
120
179
|
value: value[1..-1].chomp.force_encoding('UTF-8'),
|
180
|
+
inline: value.strip != lines[lineno - 1],
|
121
181
|
sl: lineno,
|
122
182
|
el: lineno,
|
123
183
|
sc: char_pos,
|
@@ -634,10 +694,6 @@ class Prettier::Parser < Ripper
|
|
634
694
|
# foo.(1, 2, 3)
|
635
695
|
#
|
636
696
|
def on_call(receiver, oper, sending)
|
637
|
-
# Make sure we take the operator out of the scanner events so that it
|
638
|
-
# doesn't get confused for a unary operator later.
|
639
|
-
scanner_events.delete(oper)
|
640
|
-
|
641
697
|
ending = sending
|
642
698
|
|
643
699
|
if sending == :call
|
@@ -740,11 +796,6 @@ class Prettier::Parser < Ripper
|
|
740
796
|
# of the method, the operator being used to send the method, the name of
|
741
797
|
# the method, and the arguments being passed to the method.
|
742
798
|
def on_command_call(receiver, oper, ident, args)
|
743
|
-
# Make sure we take the operator out of the scanner events so that it
|
744
|
-
# doesn't get confused for a unary operator later.
|
745
|
-
scanner_events.delete(oper)
|
746
|
-
|
747
|
-
# Grab the ending from either the arguments or the method being sent
|
748
799
|
ending = args || ident
|
749
800
|
|
750
801
|
{
|
@@ -1770,8 +1821,8 @@ class Prettier::Parser < Ripper
|
|
1770
1821
|
def bind_end(ec)
|
1771
1822
|
merge!(ec: ec)
|
1772
1823
|
|
1773
|
-
stmts = self[:body][
|
1774
|
-
consequent = self[:body][
|
1824
|
+
stmts = self[:body][1]
|
1825
|
+
consequent = self[:body][2]
|
1775
1826
|
|
1776
1827
|
if consequent
|
1777
1828
|
consequent.bind_end(ec)
|
@@ -1786,16 +1837,30 @@ class Prettier::Parser < Ripper
|
|
1786
1837
|
# inside of a bodystmt.
|
1787
1838
|
def on_rescue(exceptions, variable, stmts, consequent)
|
1788
1839
|
beging = find_scanner_event(:@kw, 'rescue')
|
1840
|
+
exceptions = exceptions[0] if exceptions.is_a?(Array)
|
1789
1841
|
|
1790
|
-
|
1791
|
-
last_node = variable || last_exception || beging
|
1792
|
-
|
1842
|
+
last_node = variable || exceptions || beging
|
1793
1843
|
stmts.bind(find_next_statement_start(last_node[:ec]), char_pos)
|
1794
1844
|
|
1845
|
+
# We add an additional inner node here that ripper doesn't provide so that
|
1846
|
+
# we have a nice place to attach inline comment. But we only need it if we
|
1847
|
+
# have an exception or a variable that we're rescuing.
|
1848
|
+
rescue_ex =
|
1849
|
+
if exceptions || variable
|
1850
|
+
{
|
1851
|
+
type: :rescue_ex,
|
1852
|
+
body: [exceptions, variable],
|
1853
|
+
sl: beging[:sl],
|
1854
|
+
sc: beging[:ec] + 1,
|
1855
|
+
el: last_node[:el],
|
1856
|
+
ec: last_node[:ec]
|
1857
|
+
}
|
1858
|
+
end
|
1859
|
+
|
1795
1860
|
Rescue.new(
|
1796
1861
|
beging.merge!(
|
1797
1862
|
type: :rescue,
|
1798
|
-
body: [
|
1863
|
+
body: [rescue_ex, stmts, consequent],
|
1799
1864
|
el: lineno,
|
1800
1865
|
ec: char_pos
|
1801
1866
|
)
|
@@ -1894,12 +1959,21 @@ class Prettier::Parser < Ripper
|
|
1894
1959
|
# propagate that onto void_stmt nodes inside the stmts in order to make sure
|
1895
1960
|
# all comments get printed appropriately.
|
1896
1961
|
class Stmts < SimpleDelegator
|
1962
|
+
attr_reader :parser
|
1963
|
+
|
1964
|
+
def initialize(parser, values)
|
1965
|
+
@parser = parser
|
1966
|
+
__setobj__(values)
|
1967
|
+
end
|
1968
|
+
|
1897
1969
|
def bind(sc, ec)
|
1898
1970
|
merge!(sc: sc, ec: ec)
|
1899
1971
|
|
1900
1972
|
if self[:body][0][:type] == :void_stmt
|
1901
1973
|
self[:body][0].merge!(sc: sc, ec: sc)
|
1902
1974
|
end
|
1975
|
+
|
1976
|
+
attach_comments(sc, ec)
|
1903
1977
|
end
|
1904
1978
|
|
1905
1979
|
def bind_end(ec)
|
@@ -1916,6 +1990,22 @@ class Prettier::Parser < Ripper
|
|
1916
1990
|
self[:body] << statement
|
1917
1991
|
self
|
1918
1992
|
end
|
1993
|
+
|
1994
|
+
private
|
1995
|
+
|
1996
|
+
def attach_comments(sc, ec)
|
1997
|
+
attachable =
|
1998
|
+
parser.comments.select do |comment|
|
1999
|
+
comment[:type] == :@comment && !comment[:inline] &&
|
2000
|
+
sc <= comment[:sc] && ec >= comment[:ec] &&
|
2001
|
+
!comment[:value].include?('prettier-ignore')
|
2002
|
+
end
|
2003
|
+
|
2004
|
+
return if attachable.empty?
|
2005
|
+
|
2006
|
+
parser.comments -= attachable
|
2007
|
+
self[:body] = (self[:body] + attachable).sort_by! { |node| node[:sc] }
|
2008
|
+
end
|
1919
2009
|
end
|
1920
2010
|
|
1921
2011
|
# stmts_new is a parser event that represents the beginning of a list of
|
@@ -1923,6 +2013,7 @@ class Prettier::Parser < Ripper
|
|
1923
2013
|
# stmts_add events, which we'll append onto an array body.
|
1924
2014
|
def on_stmts_new
|
1925
2015
|
Stmts.new(
|
2016
|
+
self,
|
1926
2017
|
type: :stmts,
|
1927
2018
|
body: [],
|
1928
2019
|
sl: lineno,
|
@@ -2173,7 +2264,7 @@ class Prettier::Parser < Ripper
|
|
2173
2264
|
# stack. So we need to explicitly disallow those operators.
|
2174
2265
|
index =
|
2175
2266
|
scanner_events.rindex do |scanner_event|
|
2176
|
-
scanner_event[:type] == :@op &&
|
2267
|
+
scanner_event[:type] == :@op && scanner_event[:sc] < value[:sc] &&
|
2177
2268
|
!%w[.. ...].include?(scanner_event[:body])
|
2178
2269
|
end
|
2179
2270
|
|
@@ -2551,24 +2642,3 @@ class Prettier::Parser < Ripper
|
|
2551
2642
|
find_scanner_event(:@kw, 'super').merge!(type: :zsuper)
|
2552
2643
|
end
|
2553
2644
|
end
|
2554
|
-
|
2555
|
-
# If this is the main file we're executing, then most likely this is being
|
2556
|
-
# executed from the parser.js spawn. In that case, read the ruby source from
|
2557
|
-
# stdin and report back the AST over stdout.
|
2558
|
-
|
2559
|
-
if $0 == __FILE__
|
2560
|
-
builder = Prettier::Parser.new($stdin.read)
|
2561
|
-
response = builder.parse
|
2562
|
-
|
2563
|
-
if !response || builder.error?
|
2564
|
-
warn(
|
2565
|
-
'@prettier/plugin-ruby encountered an error when attempting to parse ' \
|
2566
|
-
'the ruby source. This usually means there was a syntax error in the ' \
|
2567
|
-
'file in question. You can verify by running `ruby -i [path/to/file]`.'
|
2568
|
-
)
|
2569
|
-
|
2570
|
-
exit 1
|
2571
|
-
end
|
2572
|
-
|
2573
|
-
puts JSON.fast_generate(response)
|
2574
|
-
end
|