prettier 0.21.0 → 0.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/CONTRIBUTING.md +3 -3
- data/README.md +4 -0
- data/package.json +3 -3
- data/src/embed.js +20 -5
- data/src/nodes.js +5 -2
- data/src/nodes/alias.js +29 -31
- data/src/nodes/aref.js +26 -26
- data/src/nodes/args.js +56 -28
- data/src/nodes/arrays.js +142 -104
- data/src/nodes/assign.js +30 -30
- data/src/nodes/blocks.js +8 -3
- data/src/nodes/calls.js +108 -53
- data/src/nodes/class.js +74 -0
- data/src/nodes/commands.js +36 -31
- data/src/nodes/conditionals.js +42 -28
- data/src/nodes/constants.js +39 -21
- data/src/nodes/flow.js +11 -1
- data/src/nodes/hashes.js +60 -87
- data/src/nodes/heredocs.js +34 -0
- data/src/nodes/hooks.js +16 -19
- data/src/nodes/ints.js +33 -20
- data/src/nodes/lambdas.js +15 -12
- data/src/nodes/loops.js +6 -2
- data/src/nodes/massign.js +87 -65
- data/src/nodes/methods.js +46 -73
- data/src/nodes/operators.js +66 -46
- data/src/nodes/params.js +12 -14
- data/src/nodes/patterns.js +108 -33
- data/src/nodes/regexp.js +22 -13
- data/src/nodes/rescue.js +72 -59
- data/src/nodes/statements.js +23 -1
- data/src/nodes/strings.js +89 -80
- data/src/nodes/super.js +35 -0
- data/src/nodes/undef.js +42 -0
- data/src/parser.js +71 -0
- data/src/parser.rb +2269 -625
- data/src/printer.js +88 -0
- data/src/ruby.js +4 -20
- data/src/toProc.js +2 -2
- data/src/utils.js +10 -86
- data/src/utils/literalLineNoBreak.js +7 -0
- metadata +9 -5
- data/src/nodes/scopes.js +0 -61
- data/src/parse.js +0 -37
- data/src/print.js +0 -23
data/src/nodes/arrays.js
CHANGED
@@ -1,40 +1,72 @@
|
|
1
1
|
const {
|
2
2
|
concat,
|
3
3
|
group,
|
4
|
+
hardline,
|
4
5
|
ifBreak,
|
5
6
|
indent,
|
6
7
|
join,
|
7
8
|
line,
|
8
|
-
literalline,
|
9
9
|
softline
|
10
10
|
} = require("../prettier");
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
// Checks that every argument within this args node is a string_literal node
|
13
|
+
// that has no spaces or interpolations. This means we're dealing with an array
|
14
|
+
// that looks something like:
|
15
|
+
//
|
16
|
+
// ['a', 'b', 'c']
|
17
|
+
//
|
18
|
+
function isStringArray(args) {
|
19
|
+
return args.body.every((arg) => {
|
20
|
+
// We want to verify that every node inside of this array is a string
|
21
|
+
// literal. We also want to make sure none of them have comments attached.
|
22
|
+
if (arg.type !== "string_literal" || arg.comments) {
|
23
|
+
return false;
|
24
|
+
}
|
25
|
+
|
26
|
+
// If the string has multiple parts (meaning plain string content but also
|
27
|
+
// interpolated content) then we know it's not a simple string.
|
28
|
+
if (arg.body.length !== 1) {
|
29
|
+
return false;
|
30
|
+
}
|
24
31
|
|
25
|
-
const
|
26
|
-
args.body.every((arg) => arg.type === "symbol_literal");
|
32
|
+
const part = arg.body[0];
|
27
33
|
|
28
|
-
|
29
|
-
|
34
|
+
// If the only part of this string is not @tstring_content then it's
|
35
|
+
// interpolated, so again we can return false.
|
36
|
+
if (part.type !== "@tstring_content") {
|
37
|
+
return false;
|
38
|
+
}
|
30
39
|
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
// Finally, verify that the string doesn't contain a space or an escape
|
41
|
+
// character so that we know it can be put into a string literal array.
|
42
|
+
return !part.body.includes(" ") && !part.body.includes("\\");
|
43
|
+
});
|
44
|
+
}
|
45
|
+
|
46
|
+
// Checks that every argument within this args node is a symbol_literal node (as
|
47
|
+
// opposed to a dyna_symbol) so it has no interpolation. This means we're
|
48
|
+
// dealing with an array that looks something like:
|
49
|
+
//
|
50
|
+
// [:a, :b, :c]
|
51
|
+
//
|
52
|
+
function isSymbolArray(args) {
|
53
|
+
return args.body.every(
|
54
|
+
(arg) => arg.type === "symbol_literal" && !arg.comments
|
34
55
|
);
|
35
|
-
|
36
|
-
|
37
|
-
|
56
|
+
}
|
57
|
+
|
58
|
+
// Prints out a word that is a part of a special array literal that accepts
|
59
|
+
// interpolation. The body is an array of either plain strings or interpolated
|
60
|
+
// expressions.
|
61
|
+
function printSpecialArrayWord(path, opts, print) {
|
62
|
+
return concat(path.map(print, "body"));
|
63
|
+
}
|
64
|
+
|
65
|
+
// Prints out a special array literal. Accepts the parts of the array literal as
|
66
|
+
// an argument, where the first element of the parts array is a string that
|
67
|
+
// contains the special start.
|
68
|
+
function printSpecialArrayParts(parts) {
|
69
|
+
return group(
|
38
70
|
concat([
|
39
71
|
parts[0],
|
40
72
|
"[",
|
@@ -42,93 +74,99 @@ const printSpecialArray = (parts) =>
|
|
42
74
|
concat([softline, "]"])
|
43
75
|
])
|
44
76
|
);
|
45
|
-
|
46
|
-
|
47
|
-
//
|
48
|
-
//
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
77
|
+
}
|
78
|
+
|
79
|
+
// Generates a print function with an embedded special start character for the
|
80
|
+
// specific type of array literal that we're dealing with. The print function
|
81
|
+
// returns an array as it expects to eventually be handed off to
|
82
|
+
// printSpecialArrayParts.
|
83
|
+
function printSpecialArray(start) {
|
84
|
+
return function printSpecialArrayWithStart(path, opts, print) {
|
85
|
+
return [start].concat(path.map(print, "body"));
|
86
|
+
};
|
87
|
+
}
|
88
|
+
|
89
|
+
function printEmptyArrayWithComments(path, opts) {
|
90
|
+
const arrayNode = path.getValue();
|
91
|
+
|
92
|
+
const printComment = (commentPath, index) => {
|
93
|
+
arrayNode.comments[index].printed = true;
|
94
|
+
return opts.printer.printComment(commentPath);
|
95
|
+
};
|
96
|
+
|
97
|
+
return concat([
|
98
|
+
"[",
|
99
|
+
indent(
|
100
|
+
concat([hardline, join(hardline, path.map(printComment, "comments"))])
|
101
|
+
),
|
102
|
+
line,
|
103
|
+
"]"
|
104
|
+
]);
|
105
|
+
}
|
106
|
+
|
107
|
+
// An array node is any literal array in Ruby. This includes all of the special
|
108
|
+
// array literals as well as regular arrays. If it is a special array literal
|
109
|
+
// then it will have one child that represents the special array, otherwise it
|
110
|
+
// will have one child that contains all of the elements of the array.
|
111
|
+
function printArray(path, opts, print) {
|
112
|
+
const array = path.getValue();
|
113
|
+
const args = array.body[0];
|
114
|
+
|
115
|
+
// If there is no inner arguments node, then we're dealing with an empty
|
116
|
+
// array, so we can go ahead and return.
|
117
|
+
if (args === null) {
|
118
|
+
return array.comments ? printEmptyArrayWithComments(path, opts) : "[]";
|
55
119
|
}
|
56
120
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
);
|
63
|
-
};
|
121
|
+
// If we have an array that contains only simple string literals with no
|
122
|
+
// spaces or interpolation, then we're going to print a %w array.
|
123
|
+
if (isStringArray(args)) {
|
124
|
+
const printString = (stringPath) => stringPath.call(print, "body", 0);
|
125
|
+
const parts = path.map(printString, "body", 0, "body");
|
64
126
|
|
65
|
-
|
66
|
-
|
67
|
-
const args = path.getValue().body[0];
|
127
|
+
return printSpecialArrayParts(["%w"].concat(parts));
|
128
|
+
}
|
68
129
|
|
69
|
-
|
70
|
-
|
71
|
-
|
130
|
+
// If we have an array that contains only simple symbol literals with no
|
131
|
+
// interpolation, then we're going to print a %i array.
|
132
|
+
if (isSymbolArray(args)) {
|
133
|
+
const printSymbol = (symbolPath) => symbolPath.call(print, "body", 0);
|
134
|
+
const parts = path.map(printSymbol, "body", 0, "body");
|
72
135
|
|
73
|
-
|
74
|
-
|
75
|
-
["%w"].concat(getSpecialArrayParts(path, print, args))
|
76
|
-
);
|
77
|
-
}
|
136
|
+
return printSpecialArrayParts(["%i"].concat(parts));
|
137
|
+
}
|
78
138
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
139
|
+
// If we don't have a regular args node at this point then we have a special
|
140
|
+
// array literal. In that case we're going to print out the body (which will
|
141
|
+
// return to us an array with the first one being the start of the array) and
|
142
|
+
// send that over to the printSpecialArrayParts function.
|
143
|
+
if (!["args", "args_add_star"].includes(args.type)) {
|
144
|
+
return printSpecialArrayParts(path.call(print, "body", 0));
|
145
|
+
}
|
84
146
|
|
85
|
-
|
86
|
-
|
87
|
-
|
147
|
+
// Here we have a normal array of any type of object with no special literal
|
148
|
+
// types or anything.
|
149
|
+
return group(
|
150
|
+
concat([
|
151
|
+
"[",
|
152
|
+
indent(
|
153
|
+
concat([
|
154
|
+
softline,
|
155
|
+
join(concat([",", line]), path.call(print, "body", 0)),
|
156
|
+
opts.addTrailingCommas ? ifBreak(",", "") : ""
|
157
|
+
])
|
158
|
+
),
|
159
|
+
softline,
|
160
|
+
"]"
|
161
|
+
])
|
162
|
+
);
|
163
|
+
}
|
88
164
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
// opposed to at the end).
|
97
|
-
elements.forEach(({ element, elementPath }, index) => {
|
98
|
-
const isInner = index !== elements.length - 1;
|
99
|
-
|
100
|
-
if (element.type === "heredoc") {
|
101
|
-
normalDocs.push(
|
102
|
-
element.beging,
|
103
|
-
isInner || addTrailingCommas ? "," : "",
|
104
|
-
literalline,
|
105
|
-
concat(
|
106
|
-
path.map.apply(path, [print].concat(elementPath).concat("body"))
|
107
|
-
),
|
108
|
-
element.ending,
|
109
|
-
isInner ? line : ""
|
110
|
-
);
|
111
|
-
} else {
|
112
|
-
normalDocs.push(elementDocs[index]);
|
113
|
-
|
114
|
-
if (isInner) {
|
115
|
-
normalDocs.push(concat([",", line]));
|
116
|
-
} else if (addTrailingCommas) {
|
117
|
-
normalDocs.push(ifBreak(",", ""));
|
118
|
-
}
|
119
|
-
}
|
120
|
-
});
|
121
|
-
|
122
|
-
return group(
|
123
|
-
concat([
|
124
|
-
"[",
|
125
|
-
indent(concat([softline].concat(normalDocs))),
|
126
|
-
concat([softline, "]"])
|
127
|
-
])
|
128
|
-
);
|
129
|
-
},
|
130
|
-
qsymbols: makeArray("%i"),
|
131
|
-
qwords: makeArray("%w"),
|
132
|
-
symbols: makeArray("%I"),
|
133
|
-
words: makeArray("%W")
|
165
|
+
module.exports = {
|
166
|
+
array: printArray,
|
167
|
+
qsymbols: printSpecialArray("%i"),
|
168
|
+
qwords: printSpecialArray("%w"),
|
169
|
+
symbols: printSpecialArray("%I"),
|
170
|
+
word: printSpecialArrayWord,
|
171
|
+
words: printSpecialArray("%W")
|
134
172
|
};
|
data/src/nodes/assign.js
CHANGED
@@ -1,39 +1,39 @@
|
|
1
1
|
const { concat, group, indent, join, line } = require("../prettier");
|
2
2
|
const { concatBody, first, skipAssignIndent } = require("../utils");
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
function printAssign(path, opts, print) {
|
5
|
+
const [_targetNode, valueNode] = path.getValue().body;
|
6
|
+
const [targetDoc, valueDoc] = path.map(print, "body");
|
7
|
+
|
8
|
+
let rightSideDoc = valueDoc;
|
9
|
+
|
10
|
+
// If the right side of this assignment is a multiple assignment, then we need
|
11
|
+
// to join it together with commas.
|
12
|
+
if (["mrhs_add_star", "mrhs_new_from_args"].includes(valueNode.type)) {
|
13
|
+
rightSideDoc = group(join(concat([",", line]), valueDoc));
|
14
|
+
}
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
)
|
13
|
-
) {
|
14
|
-
adjustedValue = group(join(concat([",", line]), printedValue));
|
15
|
-
}
|
16
|
+
if (skipAssignIndent(valueNode)) {
|
17
|
+
return group(concat([targetDoc, " = ", rightSideDoc]));
|
18
|
+
}
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
}
|
20
|
+
return group(concat([targetDoc, " =", indent(concat([line, rightSideDoc]))]));
|
21
|
+
}
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
])
|
36
|
-
),
|
23
|
+
function printOpAssign(path, opts, print) {
|
24
|
+
return group(
|
25
|
+
concat([
|
26
|
+
path.call(print, "body", 0),
|
27
|
+
" ",
|
28
|
+
path.call(print, "body", 1),
|
29
|
+
indent(concat([line, path.call(print, "body", 2)]))
|
30
|
+
])
|
31
|
+
);
|
32
|
+
}
|
33
|
+
|
34
|
+
module.exports = {
|
35
|
+
assign: printAssign,
|
36
|
+
opassign: printOpAssign,
|
37
37
|
var_field: concatBody,
|
38
38
|
var_ref: first
|
39
39
|
};
|
data/src/nodes/blocks.js
CHANGED
@@ -16,7 +16,11 @@ const printBlock = (braces) => (path, opts, print) => {
|
|
16
16
|
statements.type === "stmts" ? statements.body : statements.body[0].body;
|
17
17
|
|
18
18
|
let doBlockBody = "";
|
19
|
-
if (
|
19
|
+
if (
|
20
|
+
stmts.length !== 1 ||
|
21
|
+
stmts[0].type !== "void_stmt" ||
|
22
|
+
stmts[0].comments
|
23
|
+
) {
|
20
24
|
doBlockBody = indent(concat([softline, path.call(print, "body", 1)]));
|
21
25
|
}
|
22
26
|
|
@@ -37,8 +41,9 @@ const printBlock = (braces) => (path, opts, print) => {
|
|
37
41
|
// We can hit this next pattern if within the block the only statement is a
|
38
42
|
// comment.
|
39
43
|
if (
|
40
|
-
stmts.length
|
41
|
-
stmts.
|
44
|
+
stmts.length === 1 &&
|
45
|
+
stmts[0].type === "void_stmt" &&
|
46
|
+
stmts[0].comments
|
42
47
|
) {
|
43
48
|
return concat([breakParent, doBlock]);
|
44
49
|
}
|
data/src/nodes/calls.js
CHANGED
@@ -1,64 +1,119 @@
|
|
1
|
-
const {
|
2
|
-
|
1
|
+
const {
|
2
|
+
concat,
|
3
|
+
group,
|
4
|
+
hardline,
|
5
|
+
ifBreak,
|
6
|
+
indent,
|
7
|
+
softline
|
8
|
+
} = require("../prettier");
|
3
9
|
const { concatBody, first, makeCall } = require("../utils");
|
4
10
|
|
11
|
+
const toProc = require("../toProc");
|
12
|
+
|
13
|
+
const chained = ["call", "method_add_arg"];
|
5
14
|
const noIndent = ["array", "hash", "if", "method_add_block", "xstring_literal"];
|
6
15
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
const printedReceiver = path.call(print, "body", 0);
|
12
|
-
const printedOperator = makeCall(path, opts, print);
|
13
|
-
|
14
|
-
// You can call lambdas with a special syntax that looks like func.(*args).
|
15
|
-
// In this case, "call" is returned for the 3rd child node.
|
16
|
-
const printedMessage =
|
17
|
-
messageNode === "call" ? messageNode : path.call(print, "body", 2);
|
18
|
-
|
19
|
-
// If we have a heredoc as a receiver, then we need to move the operator and
|
20
|
-
// the message up to start of the heredoc declaration, as in:
|
21
|
-
//
|
22
|
-
// <<~TEXT.strip
|
23
|
-
// content
|
24
|
-
// TEXT
|
25
|
-
if (receiverNode.type === "heredoc") {
|
26
|
-
return concat([
|
27
|
-
receiverNode.beging,
|
28
|
-
printedOperator,
|
29
|
-
printedMessage,
|
30
|
-
literalline,
|
31
|
-
concat(path.map(print, "body", 0, "body")),
|
32
|
-
receiverNode.ending
|
33
|
-
]);
|
34
|
-
}
|
16
|
+
function printCall(path, opts, print) {
|
17
|
+
const callNode = path.getValue();
|
18
|
+
const [receiverNode, _operatorNode, messageNode] = callNode.body;
|
35
19
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
20
|
+
const receiverDoc = path.call(print, "body", 0);
|
21
|
+
const operatorDoc = makeCall(path, opts, print);
|
22
|
+
|
23
|
+
// You can call lambdas with a special syntax that looks like func.(*args).
|
24
|
+
// In this case, "call" is returned for the 3rd child node.
|
25
|
+
const messageDoc =
|
26
|
+
messageNode === "call" ? messageNode : path.call(print, "body", 2);
|
27
|
+
|
28
|
+
// For certain left sides of the call nodes, we want to attach directly to
|
29
|
+
// the } or end.
|
30
|
+
if (noIndent.includes(receiverNode.type)) {
|
31
|
+
return concat([receiverDoc, operatorDoc, messageDoc]);
|
32
|
+
}
|
41
33
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
34
|
+
// The right side of the call node, as in everything including the operator
|
35
|
+
// and beyond.
|
36
|
+
const rightSideDoc = indent(
|
37
|
+
concat([
|
38
|
+
receiverNode.comments ? hardline : softline,
|
39
|
+
operatorDoc,
|
40
|
+
messageDoc
|
41
|
+
])
|
42
|
+
);
|
43
|
+
|
44
|
+
// Get a reference to the parent node so we can check if we're inside a chain
|
45
|
+
const parentNode = path.getParentNode();
|
46
|
+
|
47
|
+
// If our parent node is a chained node then we're not going to group the
|
48
|
+
// right side of the expression, as we want to have a nice multi-line layout.
|
49
|
+
if (chained.includes(parentNode.type)) {
|
50
|
+
parentNode.chain = (callNode.chain || 0) + 1;
|
51
|
+
parentNode.breakDoc = (callNode.breakDoc || [receiverDoc]).concat(
|
52
|
+
rightSideDoc
|
47
53
|
);
|
48
|
-
}
|
49
|
-
fcall: concatBody,
|
50
|
-
method_add_arg: (path, opts, print) => {
|
51
|
-
const [method, args] = path.map(print, "body");
|
52
|
-
const argNode = path.getValue().body[1];
|
53
|
-
|
54
|
-
// This case will ONLY be hit if we can successfully turn the block into a
|
55
|
-
// to_proc call. In that case, we just explicitly add the parens around it.
|
56
|
-
if (argNode.type === "args" && args.length > 0) {
|
57
|
-
return concat([method, "("].concat(args).concat(")"));
|
58
|
-
}
|
54
|
+
}
|
59
55
|
|
60
|
-
|
61
|
-
|
56
|
+
// If we're at the top of a chain, then we're going to print out a nice
|
57
|
+
// multi-line layout if this doesn't break into multiple lines.
|
58
|
+
if (!chained.includes(parentNode.type) && (callNode.chain || 0) >= 3) {
|
59
|
+
return ifBreak(
|
60
|
+
group(concat(callNode.breakDoc.concat(rightSideDoc))),
|
61
|
+
concat([receiverDoc, group(rightSideDoc)])
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
return group(concat([receiverDoc, group(rightSideDoc)]));
|
66
|
+
}
|
67
|
+
|
68
|
+
function printMethodAddArg(path, opts, print) {
|
69
|
+
const methodAddArgNode = path.getValue();
|
70
|
+
const argNode = methodAddArgNode.body[1];
|
71
|
+
|
72
|
+
const [methodDoc, argsDoc] = path.map(print, "body");
|
73
|
+
|
74
|
+
// You can end up here if you have a method with a ? ending, presumably
|
75
|
+
// because the parser knows that it cannot be a local variable.
|
76
|
+
if (argsDoc.length === 0) {
|
77
|
+
return methodDoc;
|
78
|
+
}
|
79
|
+
|
80
|
+
// This case will ONLY be hit if we can successfully turn the block into a
|
81
|
+
// to_proc call. In that case, we just explicitly add the parens around it.
|
82
|
+
if (argNode.type === "args" && argsDoc.length > 0) {
|
83
|
+
return concat([methodDoc, "("].concat(argsDoc).concat(")"));
|
84
|
+
}
|
85
|
+
|
86
|
+
// Get a reference to the parent node so we can check if we're inside a chain
|
87
|
+
const parentNode = path.getParentNode();
|
88
|
+
|
89
|
+
// If our parent node is a chained node then we're not going to group the
|
90
|
+
// right side of the expression, as we want to have a nice multi-line layout.
|
91
|
+
if (chained.includes(parentNode.type)) {
|
92
|
+
parentNode.chain = (methodAddArgNode.chain || 0) + 1;
|
93
|
+
parentNode.breakDoc = (methodAddArgNode.breakDoc || [methodDoc]).concat(
|
94
|
+
argsDoc
|
95
|
+
);
|
96
|
+
}
|
97
|
+
|
98
|
+
// If we're at the top of a chain, then we're going to print out a nice
|
99
|
+
// multi-line layout if this doesn't break into multiple lines.
|
100
|
+
if (
|
101
|
+
!chained.includes(parentNode.type) &&
|
102
|
+
(methodAddArgNode.chain || 0) >= 3
|
103
|
+
) {
|
104
|
+
return ifBreak(
|
105
|
+
group(concat(methodAddArgNode.breakDoc.concat(argsDoc))),
|
106
|
+
concat([methodDoc, argsDoc])
|
107
|
+
);
|
108
|
+
}
|
109
|
+
|
110
|
+
return concat([methodDoc, argsDoc]);
|
111
|
+
}
|
112
|
+
|
113
|
+
module.exports = {
|
114
|
+
call: printCall,
|
115
|
+
fcall: concatBody,
|
116
|
+
method_add_arg: printMethodAddArg,
|
62
117
|
method_add_block: (path, opts, print) => {
|
63
118
|
const [method, block] = path.getValue().body;
|
64
119
|
const proc = toProc(path, opts, block);
|