prettier 0.20.0 → 1.0.0.pre.rc2
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 +118 -4
- data/CONTRIBUTING.md +8 -6
- data/README.md +67 -60
- data/node_modules/prettier/bin-prettier.js +12317 -50112
- data/node_modules/prettier/index.js +33352 -27419
- data/node_modules/prettier/third-party.js +5678 -7676
- data/package.json +4 -4
- data/src/embed.js +27 -8
- data/src/nodes.js +6 -2
- data/src/nodes/alias.js +65 -24
- data/src/nodes/aref.js +55 -0
- data/src/nodes/args.js +55 -47
- data/src/nodes/arrays.js +150 -137
- data/src/nodes/assign.js +32 -32
- data/src/nodes/blocks.js +8 -3
- data/src/nodes/calls.js +129 -70
- 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 +48 -46
- data/src/nodes/constants.js +39 -21
- data/src/nodes/flow.js +45 -17
- data/src/nodes/hashes.js +126 -112
- data/src/nodes/heredocs.js +34 -0
- data/src/nodes/hooks.js +36 -7
- data/src/nodes/ints.js +27 -20
- data/src/nodes/lambdas.js +69 -52
- data/src/nodes/loops.js +19 -29
- 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 +38 -14
- data/src/nodes/rescue.js +72 -59
- data/src/nodes/statements.js +86 -44
- data/src/nodes/strings.js +94 -90
- data/src/nodes/super.js +35 -0
- data/src/nodes/undef.js +42 -0
- data/src/parser.js +71 -0
- data/src/parser.rb +2554 -0
- data/src/printer.js +90 -0
- data/src/ruby.js +20 -61
- data/src/toProc.js +4 -4
- data/src/utils.js +24 -88
- data/src/utils/inlineEnsureParens.js +42 -0
- data/src/utils/isEmptyStmts.js +7 -0
- data/src/utils/literalLineNoBreak.js +7 -0
- metadata +15 -20
- data/src/haml.js +0 -21
- data/src/haml/embed.js +0 -58
- data/src/haml/nodes/comment.js +0 -27
- data/src/haml/nodes/doctype.js +0 -32
- data/src/haml/nodes/filter.js +0 -16
- data/src/haml/nodes/hamlComment.js +0 -21
- data/src/haml/nodes/script.js +0 -29
- data/src/haml/nodes/silentScript.js +0 -59
- data/src/haml/nodes/tag.js +0 -157
- data/src/haml/parse.js +0 -18
- data/src/haml/parse.rb +0 -64
- data/src/haml/print.js +0 -38
- data/src/nodes/scopes.js +0 -61
- data/src/parse.js +0 -37
- data/src/print.js +0 -23
- data/src/ripper.rb +0 -811
@@ -0,0 +1,34 @@
|
|
1
|
+
const { concat, group, lineSuffix, join } = require("../prettier");
|
2
|
+
const { literalLineNoBreak } = require("../utils");
|
3
|
+
|
4
|
+
function printHeredoc(path, opts, print) {
|
5
|
+
const { body, ending } = path.getValue();
|
6
|
+
|
7
|
+
const parts = body.map((part, index) => {
|
8
|
+
if (part.type !== "@tstring_content") {
|
9
|
+
// In this case, the part of the string is an embedded expression
|
10
|
+
return path.call(print, "body", index);
|
11
|
+
}
|
12
|
+
|
13
|
+
// In this case, the part of the string is just regular string content
|
14
|
+
return join(literalLineNoBreak, part.body.split("\n"));
|
15
|
+
});
|
16
|
+
|
17
|
+
// We use a literalline break because matching indentation is required
|
18
|
+
// for the heredoc contents and ending. If the line suffix contains a
|
19
|
+
// break-parent, all ancestral groups are broken, and heredocs automatically
|
20
|
+
// break lines in groups they appear in. We prefer them to appear in-line if
|
21
|
+
// possible, so we use a literalline without the break-parent.
|
22
|
+
return group(
|
23
|
+
concat([
|
24
|
+
path.call(print, "beging"),
|
25
|
+
lineSuffix(
|
26
|
+
group(concat([literalLineNoBreak].concat(parts).concat(ending)))
|
27
|
+
)
|
28
|
+
])
|
29
|
+
);
|
30
|
+
}
|
31
|
+
|
32
|
+
module.exports = {
|
33
|
+
heredoc: printHeredoc
|
34
|
+
};
|
data/src/nodes/hooks.js
CHANGED
@@ -1,13 +1,42 @@
|
|
1
1
|
const { concat, group, indent, line } = require("../prettier");
|
2
|
+
const { isEmptyStmts } = require("../utils");
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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.
|
18
|
+
function printHook(name) {
|
19
|
+
return function printHookWithName(path, opts, print) {
|
20
|
+
const stmtsNode = path.getValue().body[1];
|
21
|
+
const printedStmts = path.call(print, "body", 1);
|
22
|
+
|
23
|
+
const parts = [
|
24
|
+
name,
|
25
|
+
" ",
|
26
|
+
path.call(print, "body", 0),
|
27
|
+
indent(concat([line, printedStmts])),
|
8
28
|
concat([line, "}"])
|
9
|
-
]
|
10
|
-
|
29
|
+
];
|
30
|
+
|
31
|
+
// If there are no statements but there are comments, then we want to skip
|
32
|
+
// printing the newline so that we don't end up with multiple spaces.
|
33
|
+
if (isEmptyStmts(stmtsNode) && stmtsNode.comments) {
|
34
|
+
parts[1] = indent(printedStmts);
|
35
|
+
}
|
36
|
+
|
37
|
+
return group(concat(parts));
|
38
|
+
};
|
39
|
+
}
|
11
40
|
|
12
41
|
module.exports = {
|
13
42
|
BEGIN: printHook("BEGIN"),
|
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,59 +1,76 @@
|
|
1
|
-
const {
|
2
|
-
concat,
|
3
|
-
group,
|
4
|
-
ifBreak,
|
5
|
-
indent,
|
6
|
-
line,
|
7
|
-
removeLines,
|
8
|
-
softline
|
9
|
-
} = require("../prettier");
|
1
|
+
const { concat, group, ifBreak, indent, line } = require("../prettier");
|
10
2
|
const { hasAncestor } = require("../utils");
|
11
3
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
4
|
+
// We can have our params coming in as the first child of the main lambda node,
|
5
|
+
// or if we have them wrapped in parens then they'll be one level deeper. Even
|
6
|
+
// though it's possible to omit the parens if you only have one argument, we're
|
7
|
+
// going to keep them in no matter what for consistency.
|
8
|
+
function printLambdaParams(path, print) {
|
9
|
+
let node = path.getValue().body[0];
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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];
|
16
|
+
}
|
23
17
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
path.call(print, "body", 1),
|
30
|
-
" }"
|
31
|
-
]);
|
18
|
+
// If we don't have any params at all, then we're just going to bail out and
|
19
|
+
// print nothing. This is to avoid printing an empty set of parentheses.
|
20
|
+
if (node.body.every((type) => !type)) {
|
21
|
+
return "";
|
22
|
+
}
|
32
23
|
|
33
|
-
|
34
|
-
|
35
|
-
ifBreak(
|
36
|
-
concat([
|
37
|
-
"lambda {",
|
38
|
-
noParams ? "" : concat([" |", removeLines(paramsConcat), "|"]),
|
39
|
-
indent(concat([line, path.call(print, "body", 1)])),
|
40
|
-
concat([line, "}"])
|
41
|
-
]),
|
42
|
-
inlineLambda
|
43
|
-
)
|
44
|
-
);
|
45
|
-
}
|
24
|
+
return path.call(print, "body", 0);
|
25
|
+
}
|
46
26
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
27
|
+
// Lambda nodes represent stabby lambda literals, which can come in a couple of
|
28
|
+
// flavors. They can use either braces or do...end for their block, and their
|
29
|
+
// arguments can be not present, have no parentheses for a single argument, or
|
30
|
+
// have parentheses for multiple arguments. Below are a couple of examples:
|
31
|
+
//
|
32
|
+
// -> { 1 }
|
33
|
+
// -> a { a + 1 }
|
34
|
+
// ->(a) { a + 1 }
|
35
|
+
// ->(a, b) { a + b }
|
36
|
+
// ->(a, b = 1) { a + b }
|
37
|
+
//
|
38
|
+
// -> do
|
39
|
+
// 1
|
40
|
+
// end
|
41
|
+
//
|
42
|
+
// -> a do
|
43
|
+
// a + 1
|
44
|
+
// end
|
45
|
+
//
|
46
|
+
// ->(a, b) do
|
47
|
+
// a + b
|
48
|
+
// end
|
49
|
+
//
|
50
|
+
// Generally, we're going to favor do...end for the multi-line form and braces
|
51
|
+
// for the single-line form. However, if we have an ancestor that is a command
|
52
|
+
// or command_call node, then we'll need to use braces either way because of
|
53
|
+
// operator precendence.
|
54
|
+
function printLambda(path, opts, print) {
|
55
|
+
const params = printLambdaParams(path, print);
|
56
|
+
const inCommand = hasAncestor(path, ["command", "command_call"]);
|
57
|
+
|
58
|
+
return group(
|
59
|
+
ifBreak(
|
60
|
+
concat([
|
61
|
+
"->",
|
62
|
+
params,
|
63
|
+
" ",
|
64
|
+
inCommand ? "{" : "do",
|
65
|
+
indent(concat([line, path.call(print, "body", 1)])),
|
66
|
+
line,
|
67
|
+
inCommand ? "}" : "end"
|
68
|
+
]),
|
69
|
+
concat(["->", params, " { ", path.call(print, "body", 1), " }"])
|
70
|
+
)
|
71
|
+
);
|
72
|
+
}
|
73
|
+
|
74
|
+
module.exports = {
|
75
|
+
lambda: printLambda
|
59
76
|
};
|
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,
|
@@ -7,14 +8,20 @@ const {
|
|
7
8
|
indent,
|
8
9
|
softline
|
9
10
|
} = require("../prettier");
|
11
|
+
|
10
12
|
const { containsAssignment } = require("../utils");
|
13
|
+
const inlineEnsureParens = require("../utils/inlineEnsureParens");
|
11
14
|
|
12
|
-
const printLoop = (keyword, modifier) => (path, {
|
13
|
-
const [_predicate,
|
15
|
+
const printLoop = (keyword, modifier) => (path, { rubyModifier }, print) => {
|
16
|
+
const [_predicate, stmts] = path.getValue().body;
|
14
17
|
|
15
18
|
// If the only statement inside this while loop is a void statement, then we
|
16
19
|
// can shorten to just displaying the predicate and then a semicolon.
|
17
|
-
if (
|
20
|
+
if (
|
21
|
+
stmts.body.length === 1 &&
|
22
|
+
stmts.body[0].type === "void_stmt" &&
|
23
|
+
!stmts.body[0].comments
|
24
|
+
) {
|
18
25
|
return group(
|
19
26
|
concat([
|
20
27
|
keyword,
|
@@ -26,30 +33,13 @@ const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
|
|
26
33
|
);
|
27
34
|
}
|
28
35
|
|
29
|
-
|
30
|
-
path
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
// besides a local variable then we can't inline the entire expression
|
37
|
-
// without wrapping it in parentheses. This is because the following
|
38
|
-
// expressions have different semantic meaning:
|
39
|
-
//
|
40
|
-
// hash[:key] = break :value while false
|
41
|
-
// hash[:key] = while false do break :value end
|
42
|
-
//
|
43
|
-
// The first one will not result in an empty hash, whereas the second one
|
44
|
-
// will result in `{ key: nil }`. In this case what we need to do for the
|
45
|
-
// first expression to align is wrap it in parens, as in:
|
46
|
-
//
|
47
|
-
// hash[:key] = (break :value while false)
|
48
|
-
if (["assign", "massign"].includes(path.getParentNode().type)) {
|
49
|
-
inlineParts = ["("].concat(inlineParts).concat(")");
|
50
|
-
}
|
51
|
-
|
52
|
-
const inlineLoop = concat(inlineParts);
|
36
|
+
const inlineLoop = concat(
|
37
|
+
inlineEnsureParens(path, [
|
38
|
+
path.call(print, "body", 1),
|
39
|
+
` ${keyword} `,
|
40
|
+
path.call(print, "body", 0)
|
41
|
+
])
|
42
|
+
);
|
53
43
|
|
54
44
|
// If we're in the modifier form and we're modifying a `begin`, then this is a
|
55
45
|
// special case where we need to explicitly use the modifier form because
|
@@ -77,8 +67,8 @@ const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
|
|
77
67
|
// an assignment (in which case we can't know for certain that that
|
78
68
|
// assignment doesn't impact the statements inside the loop) then we can't
|
79
69
|
// use the modifier form and we must use the block form.
|
80
|
-
if (!
|
81
|
-
return blockLoop;
|
70
|
+
if (!rubyModifier || containsAssignment(path.getValue().body[0])) {
|
71
|
+
return concat([breakParent, blockLoop]);
|
82
72
|
}
|
83
73
|
|
84
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
|
};
|