prettier 0.21.0 → 1.0.1
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 +112 -7
- data/CONTRIBUTING.md +4 -4
- data/README.md +18 -14
- data/package.json +9 -6
- data/src/embed.js +27 -8
- 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 +55 -47
- data/src/nodes/arrays.js +132 -106
- data/src/nodes/assign.js +32 -32
- data/src/nodes/blocks.js +8 -3
- data/src/nodes/calls.js +163 -60
- data/src/nodes/case.js +11 -7
- data/src/nodes/class.js +74 -0
- data/src/nodes/commands.js +36 -31
- data/src/nodes/conditionals.js +44 -30
- data/src/nodes/constants.js +39 -21
- data/src/nodes/flow.js +11 -1
- data/src/nodes/hashes.js +90 -109
- data/src/nodes/heredocs.js +34 -0
- data/src/nodes/hooks.js +21 -22
- data/src/nodes/ints.js +27 -20
- data/src/nodes/lambdas.js +14 -27
- data/src/nodes/loops.js +10 -5
- data/src/nodes/massign.js +87 -65
- data/src/nodes/methods.js +48 -73
- data/src/nodes/operators.js +70 -39
- data/src/nodes/params.js +26 -16
- data/src/nodes/patterns.js +108 -33
- data/src/nodes/regexp.js +45 -14
- data/src/nodes/rescue.js +72 -59
- data/src/nodes/statements.js +86 -44
- data/src/nodes/strings.js +95 -85
- data/src/nodes/super.js +35 -0
- data/src/nodes/undef.js +42 -0
- data/src/parser.js +86 -0
- data/src/parser.rb +2400 -621
- data/src/printer.js +90 -0
- data/src/ruby.js +19 -41
- data/src/toProc.js +4 -4
- data/src/utils.js +24 -88
- data/src/utils/literalLineNoBreak.js +7 -0
- data/src/utils/printEmptyCollection.js +42 -0
- metadata +12 -49
- data/src/nodes/scopes.js +0 -61
- data/src/parse.js +0 -37
- data/src/print.js +0 -23
data/src/nodes/hooks.js
CHANGED
@@ -1,28 +1,29 @@
|
|
1
1
|
const { concat, group, indent, line } = require("../prettier");
|
2
2
|
const { isEmptyStmts } = require("../utils");
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
*/
|
4
|
+
// The `BEGIN` and `END` keywords are used to hook into the Ruby process. Any
|
5
|
+
// `BEGIN` blocks are executed right when the process starts up, and the `END`
|
6
|
+
// blocks are executed right before exiting.
|
7
|
+
//
|
8
|
+
// BEGIN {
|
9
|
+
// # content goes here
|
10
|
+
// }
|
11
|
+
//
|
12
|
+
// END {
|
13
|
+
// # content goes here
|
14
|
+
// }
|
15
|
+
//
|
16
|
+
// Interesting side note, you don't use `do...end` blocks with these hooks. Both
|
17
|
+
// nodes contain one child which is a `stmts` node.
|
19
18
|
function printHook(name) {
|
20
|
-
function printHookWithName(path, opts, print) {
|
21
|
-
const stmtsNode = path.getValue().body[
|
22
|
-
const printedStmts = path.call(print, "body",
|
19
|
+
return function printHookWithName(path, opts, print) {
|
20
|
+
const stmtsNode = path.getValue().body[1];
|
21
|
+
const printedStmts = path.call(print, "body", 1);
|
23
22
|
|
24
23
|
const parts = [
|
25
|
-
|
24
|
+
name,
|
25
|
+
" ",
|
26
|
+
path.call(print, "body", 0),
|
26
27
|
indent(concat([line, printedStmts])),
|
27
28
|
concat([line, "}"])
|
28
29
|
];
|
@@ -34,9 +35,7 @@ function printHook(name) {
|
|
34
35
|
}
|
35
36
|
|
36
37
|
return group(concat(parts));
|
37
|
-
}
|
38
|
-
|
39
|
-
return printHookWithName;
|
38
|
+
};
|
40
39
|
}
|
41
40
|
|
42
41
|
module.exports = {
|
data/src/nodes/ints.js
CHANGED
@@ -1,24 +1,31 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
// An @int node is any literal integer in Ruby. They can come in a number of
|
2
|
+
// bases, and look like the following:
|
3
|
+
//
|
4
|
+
// Binary (2) - 0b0110
|
5
|
+
// Octal (8) - 0o34 or 034
|
6
|
+
// Decimal (10) - a normal number like 159
|
7
|
+
// Hexidecimal (16) - 0xac5
|
8
|
+
//
|
9
|
+
// If it's a decimal number, it can be optional separated by any number of
|
10
|
+
// arbitrarily places underscores. This can be useful for dollars and cents
|
11
|
+
// (34_99), dates (2020_11_30), and normal 3 digit separation (1_222_333).
|
12
|
+
function printInt(path, _opts, _print) {
|
13
|
+
const { body } = path.getValue();
|
4
14
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
}
|
15
|
+
// If the number is a base 10 number, is sufficiently large, and is not
|
16
|
+
// already formatted with underscores, then add them in in between the
|
17
|
+
// numbers every three characters starting from the right.
|
18
|
+
if (!body.startsWith("0") && body.length >= 5 && !body.includes("_")) {
|
19
|
+
return ` ${body}`
|
20
|
+
.slice((body.length + 2) % 3)
|
21
|
+
.match(/.{3}/g)
|
22
|
+
.join("_")
|
23
|
+
.trim();
|
24
|
+
}
|
10
25
|
|
11
|
-
|
12
|
-
|
13
|
-
// numbers every three characters starting from the right.
|
14
|
-
if (!body.startsWith("0") && body.length >= 5 && !body.includes("_")) {
|
15
|
-
return ` ${body}`
|
16
|
-
.slice((body.length + 2) % 3)
|
17
|
-
.match(/.{3}/g)
|
18
|
-
.join("_")
|
19
|
-
.trim();
|
20
|
-
}
|
26
|
+
return body;
|
27
|
+
}
|
21
28
|
|
22
|
-
|
23
|
-
|
29
|
+
module.exports = {
|
30
|
+
"@int": printInt
|
24
31
|
};
|
data/src/nodes/lambdas.js
CHANGED
@@ -1,41 +1,28 @@
|
|
1
|
-
const {
|
2
|
-
|
3
|
-
group,
|
4
|
-
ifBreak,
|
5
|
-
indent,
|
6
|
-
line,
|
7
|
-
softline
|
8
|
-
} = require("../prettier");
|
9
|
-
const { hasAncestor, nodeDive } = require("../utils");
|
1
|
+
const { concat, group, ifBreak, indent, line } = require("../prettier");
|
2
|
+
const { hasAncestor } = require("../utils");
|
10
3
|
|
11
4
|
// We can have our params coming in as the first child of the main lambda node,
|
12
5
|
// or if we have them wrapped in parens then they'll be one level deeper. Even
|
13
6
|
// though it's possible to omit the parens if you only have one argument, we're
|
14
7
|
// going to keep them in no matter what for consistency.
|
15
|
-
|
16
|
-
|
17
|
-
let params = nodeDive(path.getValue(), steps);
|
8
|
+
function printLambdaParams(path, print) {
|
9
|
+
let node = path.getValue().body[0];
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
// In this case we had something like -> (foo) { bar } which would mean that
|
12
|
+
// we're looking at a paren node, so we'll descend one level deeper to get at
|
13
|
+
// the actual params node.
|
14
|
+
if (node.type !== "params") {
|
15
|
+
node = node.body[0];
|
22
16
|
}
|
23
17
|
|
24
18
|
// If we don't have any params at all, then we're just going to bail out and
|
25
19
|
// print nothing. This is to avoid printing an empty set of parentheses.
|
26
|
-
if (
|
20
|
+
if (node.body.every((type) => !type)) {
|
27
21
|
return "";
|
28
22
|
}
|
29
23
|
|
30
|
-
return
|
31
|
-
|
32
|
-
"(",
|
33
|
-
indent(concat([softline, path.call.apply(path, [print].concat(steps))])),
|
34
|
-
softline,
|
35
|
-
")"
|
36
|
-
])
|
37
|
-
);
|
38
|
-
};
|
24
|
+
return path.call(print, "body", 0);
|
25
|
+
}
|
39
26
|
|
40
27
|
// Lambda nodes represent stabby lambda literals, which can come in a couple of
|
41
28
|
// flavors. They can use either braces or do...end for their block, and their
|
@@ -64,7 +51,7 @@ const printLambdaParams = (path, print) => {
|
|
64
51
|
// for the single-line form. However, if we have an ancestor that is a command
|
65
52
|
// or command_call node, then we'll need to use braces either way because of
|
66
53
|
// operator precendence.
|
67
|
-
|
54
|
+
function printLambda(path, opts, print) {
|
68
55
|
const params = printLambdaParams(path, print);
|
69
56
|
const inCommand = hasAncestor(path, ["command", "command_call"]);
|
70
57
|
|
@@ -82,7 +69,7 @@ const printLambda = (path, opts, print) => {
|
|
82
69
|
concat(["->", params, " { ", path.call(print, "body", 1), " }"])
|
83
70
|
)
|
84
71
|
);
|
85
|
-
}
|
72
|
+
}
|
86
73
|
|
87
74
|
module.exports = {
|
88
75
|
lambda: printLambda
|
data/src/nodes/loops.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
const {
|
2
2
|
align,
|
3
|
+
breakParent,
|
3
4
|
concat,
|
4
5
|
group,
|
5
6
|
hardline,
|
@@ -11,12 +12,16 @@ const {
|
|
11
12
|
const { containsAssignment } = require("../utils");
|
12
13
|
const inlineEnsureParens = require("../utils/inlineEnsureParens");
|
13
14
|
|
14
|
-
const printLoop = (keyword, modifier) => (path, {
|
15
|
-
const [_predicate,
|
15
|
+
const printLoop = (keyword, modifier) => (path, { rubyModifier }, print) => {
|
16
|
+
const [_predicate, stmts] = path.getValue().body;
|
16
17
|
|
17
18
|
// If the only statement inside this while loop is a void statement, then we
|
18
19
|
// can shorten to just displaying the predicate and then a semicolon.
|
19
|
-
if (
|
20
|
+
if (
|
21
|
+
stmts.body.length === 1 &&
|
22
|
+
stmts.body[0].type === "void_stmt" &&
|
23
|
+
!stmts.body[0].comments
|
24
|
+
) {
|
20
25
|
return group(
|
21
26
|
concat([
|
22
27
|
keyword,
|
@@ -62,8 +67,8 @@ const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
|
|
62
67
|
// an assignment (in which case we can't know for certain that that
|
63
68
|
// assignment doesn't impact the statements inside the loop) then we can't
|
64
69
|
// use the modifier form and we must use the block form.
|
65
|
-
if (!
|
66
|
-
return blockLoop;
|
70
|
+
if (!rubyModifier || containsAssignment(path.getValue().body[0])) {
|
71
|
+
return concat([breakParent, blockLoop]);
|
67
72
|
}
|
68
73
|
|
69
74
|
return group(ifBreak(blockLoop, inlineLoop));
|
data/src/nodes/massign.js
CHANGED
@@ -1,69 +1,91 @@
|
|
1
1
|
const { concat, group, indent, join, line, softline } = require("../prettier");
|
2
|
-
const { makeList } = require("../utils");
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
[
|
10
|
-
|
11
|
-
|
12
|
-
)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
if (path.getValue().body[0].comma) {
|
50
|
-
parts.push(",");
|
51
|
-
}
|
52
|
-
|
53
|
-
return group(concat(["(", indent(concat(parts)), concat([softline, ")"])]));
|
54
|
-
},
|
55
|
-
mrhs: makeList,
|
56
|
-
mrhs_add_star: (path, opts, print) =>
|
57
|
-
path
|
58
|
-
.call(print, "body", 0)
|
59
|
-
.concat([concat(["*", path.call(print, "body", 1)])]),
|
60
|
-
mrhs_new_from_args: (path, opts, print) => {
|
61
|
-
const parts = path.call(print, "body", 0);
|
62
|
-
|
63
|
-
if (path.getValue().body.length > 1) {
|
64
|
-
parts.push(path.call(print, "body", 1));
|
65
|
-
}
|
66
|
-
|
67
|
-
return parts;
|
3
|
+
function printMAssign(path, opts, print) {
|
4
|
+
let right = path.call(print, "body", 1);
|
5
|
+
|
6
|
+
if (
|
7
|
+
["mrhs_add_star", "mrhs_new_from_args"].includes(
|
8
|
+
path.getValue().body[1].type
|
9
|
+
)
|
10
|
+
) {
|
11
|
+
right = group(join(concat([",", line]), right));
|
12
|
+
}
|
13
|
+
|
14
|
+
const parts = [join(concat([",", line]), path.call(print, "body", 0))];
|
15
|
+
if (path.getValue().body[0].comma) {
|
16
|
+
parts.push(",");
|
17
|
+
}
|
18
|
+
|
19
|
+
return group(
|
20
|
+
concat([group(concat(parts)), " =", indent(concat([line, right]))])
|
21
|
+
);
|
22
|
+
}
|
23
|
+
|
24
|
+
function printMLHS(path, opts, print) {
|
25
|
+
return path.map(print, "body");
|
26
|
+
}
|
27
|
+
|
28
|
+
function printMLHSAddPost(path, opts, print) {
|
29
|
+
return path.call(print, "body", 0).concat(path.call(print, "body", 1));
|
30
|
+
}
|
31
|
+
|
32
|
+
function printMLHSAddStar(path, opts, print) {
|
33
|
+
const rightParts = ["*"];
|
34
|
+
|
35
|
+
if (path.getValue().body[1]) {
|
36
|
+
rightParts.push(path.call(print, "body", 1));
|
37
|
+
}
|
38
|
+
|
39
|
+
return path.call(print, "body", 0).concat(concat(rightParts));
|
40
|
+
}
|
41
|
+
|
42
|
+
function printMLHSParen(path, opts, print) {
|
43
|
+
if (["massign", "mlhs_paren"].includes(path.getParentNode().type)) {
|
44
|
+
// If we're nested in brackets as part of the left hand side of an
|
45
|
+
// assignment, i.e., (a, b, c) = 1, 2, 3
|
46
|
+
// ignore the current node and just go straight to the content
|
47
|
+
return path.call(print, "body", 0);
|
68
48
|
}
|
49
|
+
|
50
|
+
const parts = [
|
51
|
+
softline,
|
52
|
+
join(concat([",", line]), path.call(print, "body", 0))
|
53
|
+
];
|
54
|
+
|
55
|
+
if (path.getValue().body[0].comma) {
|
56
|
+
parts.push(",");
|
57
|
+
}
|
58
|
+
|
59
|
+
return group(concat(["(", indent(concat(parts)), concat([softline, ")"])]));
|
60
|
+
}
|
61
|
+
|
62
|
+
function printMRHS(path, opts, print) {
|
63
|
+
return path.map(print, "body");
|
64
|
+
}
|
65
|
+
|
66
|
+
function printMRHSAddStar(path, opts, print) {
|
67
|
+
const [leftDoc, rightDoc] = path.map(print, "body");
|
68
|
+
|
69
|
+
return leftDoc.concat([concat(["*", rightDoc])]);
|
70
|
+
}
|
71
|
+
|
72
|
+
function printMRHSNewFromArgs(path, opts, print) {
|
73
|
+
const parts = path.call(print, "body", 0);
|
74
|
+
|
75
|
+
if (path.getValue().body[1]) {
|
76
|
+
parts.push(path.call(print, "body", 1));
|
77
|
+
}
|
78
|
+
|
79
|
+
return parts;
|
80
|
+
}
|
81
|
+
|
82
|
+
module.exports = {
|
83
|
+
massign: printMAssign,
|
84
|
+
mlhs: printMLHS,
|
85
|
+
mlhs_add_post: printMLHSAddPost,
|
86
|
+
mlhs_add_star: printMLHSAddStar,
|
87
|
+
mlhs_paren: printMLHSParen,
|
88
|
+
mrhs: printMRHS,
|
89
|
+
mrhs_add_star: printMRHSAddStar,
|
90
|
+
mrhs_new_from_args: printMRHSNewFromArgs
|
69
91
|
};
|
data/src/nodes/methods.js
CHANGED
@@ -1,80 +1,55 @@
|
|
1
|
-
const {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
// need to include the target and the operator
|
18
|
-
if (offset > 0) {
|
19
|
-
declaration.push(path.call(print, "body", 0), path.call(print, "body", 1));
|
20
|
-
}
|
21
|
-
|
22
|
-
// In case there are no parens but there are arguments
|
23
|
-
const parens =
|
24
|
-
params.type === "params" && params.body.some((paramType) => paramType);
|
25
|
-
|
26
|
-
declaration.push(
|
27
|
-
path.call(print, "body", offset),
|
28
|
-
parens ? "(" : "",
|
29
|
-
path.call(print, "body", offset + 1),
|
30
|
-
parens ? ")" : ""
|
31
|
-
);
|
1
|
+
const { concat, group, hardline, indent } = require("../prettier");
|
2
|
+
const { first } = require("../utils");
|
3
|
+
|
4
|
+
function printMethod(offset) {
|
5
|
+
return function printMethodWithOffset(path, opts, print) {
|
6
|
+
const [_name, params, body] = path.getValue().body.slice(offset);
|
7
|
+
const declaration = ["def "];
|
8
|
+
|
9
|
+
// In this case, we're printing a method that's defined as a singleton, so
|
10
|
+
// we need to include the target and the operator
|
11
|
+
if (offset > 0) {
|
12
|
+
declaration.push(
|
13
|
+
path.call(print, "body", 0),
|
14
|
+
path.call(print, "body", 1)
|
15
|
+
);
|
16
|
+
}
|
32
17
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
18
|
+
// In case there are no parens but there are arguments
|
19
|
+
const parens =
|
20
|
+
params.type === "params" && params.body.some((paramType) => paramType);
|
21
|
+
|
22
|
+
declaration.push(
|
23
|
+
path.call(print, "body", offset),
|
24
|
+
parens ? "(" : "",
|
25
|
+
path.call(print, "body", offset + 1),
|
26
|
+
parens ? ")" : ""
|
27
|
+
);
|
28
|
+
|
29
|
+
// If the body is empty, we can replace with a ;
|
30
|
+
const stmts = body.body[0].body;
|
31
|
+
|
32
|
+
if (
|
33
|
+
!body.body.slice(1).some((node) => node) &&
|
34
|
+
stmts.length === 1 &&
|
35
|
+
stmts[0].type === "void_stmt" &&
|
36
|
+
!stmts[0].comments
|
37
|
+
) {
|
38
|
+
return group(concat(declaration.concat(["; end"])));
|
39
|
+
}
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
};
|
41
|
+
return group(
|
42
|
+
concat([
|
43
|
+
group(concat(declaration)),
|
44
|
+
indent(concat([hardline, path.call(print, "body", offset + 2)])),
|
45
|
+
group(concat([hardline, "end"]))
|
46
|
+
])
|
47
|
+
);
|
48
|
+
};
|
49
|
+
}
|
47
50
|
|
48
51
|
module.exports = {
|
49
52
|
access_ctrl: first,
|
50
53
|
def: printMethod(0),
|
51
|
-
defs: printMethod(2)
|
52
|
-
methref: (path, opts, print) => join(".:", path.map(print, "body")),
|
53
|
-
super: (path, opts, print) => {
|
54
|
-
const args = path.getValue().body[0];
|
55
|
-
|
56
|
-
if (args.type === "arg_paren") {
|
57
|
-
// In case there are explicitly no arguments but they are using parens,
|
58
|
-
// we assume they are attempting to override the initializer and pass no
|
59
|
-
// arguments up.
|
60
|
-
if (args.body[0] === null) {
|
61
|
-
return "super()";
|
62
|
-
}
|
63
|
-
|
64
|
-
return concat(["super", path.call(print, "body", 0)]);
|
65
|
-
}
|
66
|
-
|
67
|
-
return concat(["super ", join(", ", path.call(print, "body", 0))]);
|
68
|
-
},
|
69
|
-
undef: (path, opts, print) =>
|
70
|
-
group(
|
71
|
-
concat([
|
72
|
-
"undef ",
|
73
|
-
align(
|
74
|
-
"undef ".length,
|
75
|
-
join(concat([",", line]), path.map(print, "body", 0))
|
76
|
-
)
|
77
|
-
])
|
78
|
-
),
|
79
|
-
zsuper: literal("super")
|
54
|
+
defs: printMethod(2)
|
80
55
|
};
|