prettier 0.20.0 → 1.0.0.pre.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@prettier/plugin-ruby",
|
3
|
-
"version": "0.
|
3
|
+
"version": "1.0.0-rc2",
|
4
4
|
"description": "prettier plugin for the Ruby programming language",
|
5
5
|
"main": "src/ruby.js",
|
6
6
|
"scripts": {
|
@@ -23,9 +23,9 @@
|
|
23
23
|
},
|
24
24
|
"devDependencies": {
|
25
25
|
"all-contributors-cli": "^6.14.1",
|
26
|
-
"eslint": "^7.1
|
27
|
-
"eslint-config-prettier": "^
|
28
|
-
"husky": "^
|
26
|
+
"eslint": "^7.8.1",
|
27
|
+
"eslint-config-prettier": "^7.0.0",
|
28
|
+
"husky": "^5.0.4",
|
29
29
|
"jest": "^26.0.0",
|
30
30
|
"pretty-quick": "^3.0.0"
|
31
31
|
},
|
data/src/embed.js
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
const {
|
2
2
|
concat,
|
3
|
+
group,
|
3
4
|
indent,
|
4
|
-
|
5
|
+
lineSuffix,
|
5
6
|
mapDoc,
|
6
7
|
markAsRoot,
|
7
8
|
stripTrailingHardline
|
8
9
|
} = require("./prettier");
|
9
10
|
|
11
|
+
const { literalLineNoBreak } = require("./utils");
|
12
|
+
|
10
13
|
const parsers = {
|
11
14
|
css: "css",
|
12
15
|
javascript: "babel",
|
@@ -23,12 +26,12 @@ const replaceNewlines = (doc) =>
|
|
23
26
|
? concat(
|
24
27
|
currentDoc
|
25
28
|
.split(/(\n)/g)
|
26
|
-
.map((v, i) => (i % 2 === 0 ? v :
|
29
|
+
.map((v, i) => (i % 2 === 0 ? v : literalLineNoBreak))
|
27
30
|
)
|
28
31
|
: currentDoc
|
29
32
|
);
|
30
33
|
|
31
|
-
const embed = (path,
|
34
|
+
const embed = (path, print, textToDoc, _opts) => {
|
32
35
|
const node = path.getValue();
|
33
36
|
|
34
37
|
// Currently we only support embedded formatting on heredoc nodes
|
@@ -44,7 +47,7 @@ const embed = (path, _print, textToDoc, _opts) => {
|
|
44
47
|
|
45
48
|
// Next, find the parser associated with this heredoc (if there is one). For
|
46
49
|
// example, if you use <<~CSS, we'd hook it up to the css parser.
|
47
|
-
const parser = parsers[beging.slice(3).toLowerCase()];
|
50
|
+
const parser = parsers[beging.body.slice(3).toLowerCase()];
|
48
51
|
if (!parser) {
|
49
52
|
return null;
|
50
53
|
}
|
@@ -53,19 +56,35 @@ const embed = (path, _print, textToDoc, _opts) => {
|
|
53
56
|
// into the embedded parser. Get back the doc node.
|
54
57
|
const content = body.map((part) => part.body).join("");
|
55
58
|
const formatted = concat([
|
56
|
-
|
59
|
+
literalLineNoBreak,
|
57
60
|
replaceNewlines(stripTrailingHardline(textToDoc(content, { parser })))
|
58
61
|
]);
|
59
62
|
|
60
63
|
// If we're using a squiggly heredoc, then we can properly handle indentation
|
61
64
|
// ourselves.
|
62
|
-
if (beging[2] === "~") {
|
63
|
-
return concat([
|
65
|
+
if (beging.body[2] === "~") {
|
66
|
+
return concat([
|
67
|
+
path.call(print, "beging"),
|
68
|
+
lineSuffix(
|
69
|
+
group(
|
70
|
+
concat([
|
71
|
+
indent(markAsRoot(formatted)),
|
72
|
+
literalLineNoBreak,
|
73
|
+
ending.trim()
|
74
|
+
])
|
75
|
+
)
|
76
|
+
)
|
77
|
+
]);
|
64
78
|
}
|
65
79
|
|
66
80
|
// Otherwise, we need to just assume it's formatted correctly and return the
|
67
81
|
// content as it is.
|
68
|
-
return markAsRoot(
|
82
|
+
return markAsRoot(
|
83
|
+
concat([
|
84
|
+
path.call(print, "beging"),
|
85
|
+
lineSuffix(group(concat([formatted, literalLineNoBreak, ending.trim()])))
|
86
|
+
])
|
87
|
+
);
|
69
88
|
};
|
70
89
|
|
71
90
|
module.exports = embed;
|
data/src/nodes.js
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
module.exports = Object.assign(
|
2
2
|
{},
|
3
3
|
require("./nodes/alias"),
|
4
|
+
require("./nodes/aref"),
|
4
5
|
require("./nodes/args"),
|
5
6
|
require("./nodes/arrays"),
|
6
7
|
require("./nodes/assign"),
|
7
8
|
require("./nodes/blocks"),
|
8
9
|
require("./nodes/calls"),
|
9
10
|
require("./nodes/case"),
|
11
|
+
require("./nodes/class"),
|
10
12
|
require("./nodes/commands"),
|
11
13
|
require("./nodes/conditionals"),
|
12
14
|
require("./nodes/constants"),
|
13
15
|
require("./nodes/flow"),
|
14
16
|
require("./nodes/hashes"),
|
17
|
+
require("./nodes/heredocs"),
|
15
18
|
require("./nodes/hooks"),
|
16
19
|
require("./nodes/ints"),
|
17
20
|
require("./nodes/lambdas"),
|
@@ -24,7 +27,8 @@ module.exports = Object.assign(
|
|
24
27
|
require("./nodes/regexp"),
|
25
28
|
require("./nodes/rescue"),
|
26
29
|
require("./nodes/return"),
|
27
|
-
require("./nodes/scopes"),
|
28
30
|
require("./nodes/statements"),
|
29
|
-
require("./nodes/strings")
|
31
|
+
require("./nodes/strings"),
|
32
|
+
require("./nodes/super"),
|
33
|
+
require("./nodes/undef")
|
30
34
|
);
|
data/src/nodes/alias.js
CHANGED
@@ -1,32 +1,73 @@
|
|
1
|
-
const {
|
1
|
+
const {
|
2
|
+
addTrailingComment,
|
3
|
+
align,
|
4
|
+
concat,
|
5
|
+
group,
|
6
|
+
hardline,
|
7
|
+
line
|
8
|
+
} = require("../prettier");
|
2
9
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
const identFromSymbol = (path, print, index) =>
|
9
|
-
path.call(print, "body", index, "body", 0, "body", 0);
|
10
|
+
// In general, return the printed doc of the argument at the provided index.
|
11
|
+
// Special handling is given for symbol literals that are not bare words, as we
|
12
|
+
// convert those into bare words by just pulling out the ident node.
|
13
|
+
function printAliasArgument(path, print, argIndex) {
|
14
|
+
const node = path.getValue().body[argIndex];
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
16
|
+
if (node.type === "symbol_literal") {
|
17
|
+
// If we're going to descend into the symbol literal to grab out the ident
|
18
|
+
// node, then we need to make sure we copy over any comments as well,
|
19
|
+
// otherwise we could accidentally skip printing them.
|
20
|
+
if (node.comments) {
|
21
|
+
node.comments.forEach((comment) => {
|
22
|
+
addTrailingComment(node.body[0], comment);
|
23
|
+
});
|
24
|
+
}
|
14
25
|
|
15
|
-
|
16
|
-
if (usingSymbols(path)) {
|
17
|
-
return join(" ", [
|
18
|
-
identFromSymbol(path, print, 0),
|
19
|
-
identFromSymbol(path, print, 1)
|
20
|
-
]);
|
26
|
+
return path.call(print, "body", argIndex, "body", 0);
|
21
27
|
}
|
22
|
-
return join(" ", path.map(print, "body"));
|
23
|
-
};
|
24
28
|
|
25
|
-
|
26
|
-
|
29
|
+
return path.call(print, "body", argIndex);
|
30
|
+
}
|
31
|
+
|
32
|
+
// The `alias` keyword is used to make a method respond to another name as well
|
33
|
+
// as the current one. For example, to get the method `foo` to also respond to
|
34
|
+
// `bar`, you would:
|
35
|
+
//
|
36
|
+
// alias bar foo
|
37
|
+
//
|
38
|
+
// Now, in the current context you can call `bar` and it will execute the `foo`
|
39
|
+
// method.
|
40
|
+
//
|
41
|
+
// When you're aliasing two methods, you can either provide bare words (like the
|
42
|
+
// example above) or you can provide symbols (note that this includes dynamic
|
43
|
+
// symbols like :"foo-#{bar}-baz"). In general, to be consistent with the ruby
|
44
|
+
// style guide, we prefer bare words:
|
45
|
+
//
|
46
|
+
// https://github.com/rubocop-hq/ruby-style-guide#alias-method-lexically
|
47
|
+
//
|
48
|
+
// The `alias` node contains two children. The left and right align with the
|
49
|
+
// arguments passed to the keyword. So, for the above example the left would be
|
50
|
+
// the symbol literal `bar` and the right could be the symbol literal `foo`.
|
51
|
+
function printAlias(path, opts, print) {
|
52
|
+
const keyword = "alias ";
|
53
|
+
|
54
|
+
const rightSide = concat([
|
55
|
+
// If the left child has any comments, then we need to explicitly break this
|
56
|
+
// into two lines
|
57
|
+
path.getValue().body[0].comments ? hardline : line,
|
58
|
+
printAliasArgument(path, print, 1)
|
59
|
+
]);
|
60
|
+
|
61
|
+
return group(
|
62
|
+
concat([
|
63
|
+
keyword,
|
64
|
+
printAliasArgument(path, print, 0),
|
65
|
+
group(align(keyword.length, rightSide))
|
66
|
+
])
|
67
|
+
);
|
68
|
+
}
|
27
69
|
|
28
70
|
module.exports = {
|
29
|
-
alias,
|
30
|
-
|
31
|
-
var_alias: alias
|
71
|
+
alias: printAlias,
|
72
|
+
var_alias: printAlias
|
32
73
|
};
|
data/src/nodes/aref.js
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
const { concat, group, indent, join, line, softline } = require("../prettier");
|
2
|
+
|
3
|
+
// `aref` nodes are when you're pulling a value out of a collection at a
|
4
|
+
// specific index. Put another way, it's any time you're calling the method
|
5
|
+
// `#[]`.
|
6
|
+
//
|
7
|
+
// The nodes usually contains two children, details below in the
|
8
|
+
// `printArefField` function. In some cases, you don't necessarily have the
|
9
|
+
// second child node, because you can call procs with a pretty esoteric syntax.
|
10
|
+
// In the following example, you wouldn't have a second child, and `"foo"` would
|
11
|
+
// be the first child.
|
12
|
+
//
|
13
|
+
// foo[]
|
14
|
+
//
|
15
|
+
function printAref(path, opts, print) {
|
16
|
+
const indexNode = path.getValue().body[1];
|
17
|
+
|
18
|
+
if (!indexNode) {
|
19
|
+
return concat([path.call(print, "body", 0), "[]"]);
|
20
|
+
}
|
21
|
+
|
22
|
+
return printArefField(path, opts, print);
|
23
|
+
}
|
24
|
+
|
25
|
+
// `aref_field` nodes are for assigning values into collections at specific
|
26
|
+
// indices. Put another way, it's any time you're calling the method `#[]=`.
|
27
|
+
// The `aref_field` node itself is just the left side of the assignment, and
|
28
|
+
// they're always wrapped in `assign` nodes.
|
29
|
+
//
|
30
|
+
// The nodes always contain two children, the name of the array (usually a
|
31
|
+
// `vcall` node and the index (usually an `args_add_block` node). The
|
32
|
+
// `args_add_block` is one of a couple nodes that has special handling where its
|
33
|
+
// printed form is actually an array to make joining easier.
|
34
|
+
//
|
35
|
+
// So in the following example, `"foo"` is the array and `["bar"]` is the index.
|
36
|
+
//
|
37
|
+
// foo[bar] = baz
|
38
|
+
//
|
39
|
+
function printArefField(path, opts, print) {
|
40
|
+
const [printedArray, printedIndex] = path.map(print, "body");
|
41
|
+
|
42
|
+
return group(
|
43
|
+
concat([
|
44
|
+
printedArray,
|
45
|
+
"[",
|
46
|
+
indent(concat([softline, join(concat([",", line]), printedIndex)])),
|
47
|
+
concat([softline, "]"])
|
48
|
+
])
|
49
|
+
);
|
50
|
+
}
|
51
|
+
|
52
|
+
module.exports = {
|
53
|
+
aref: printAref,
|
54
|
+
aref_field: printArefField
|
55
|
+
};
|
data/src/nodes/args.js
CHANGED
@@ -9,53 +9,56 @@ const {
|
|
9
9
|
} = require("../prettier");
|
10
10
|
|
11
11
|
const toProc = require("../toProc");
|
12
|
-
const {
|
12
|
+
const { getTrailingComma } = require("../utils");
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
if (path.getValue().body[0] === null) {
|
17
|
-
return "";
|
18
|
-
}
|
19
|
-
|
20
|
-
// Here we can skip the entire rest of the method by just checking if it's
|
21
|
-
// an args_forward node, as we're guaranteed that there are no other arg
|
22
|
-
// nodes.
|
23
|
-
if (path.getValue().body[0].type === "args_forward") {
|
24
|
-
return "(...)";
|
25
|
-
}
|
14
|
+
function printArgParen(path, opts, print) {
|
15
|
+
const argsNode = path.getValue().body[0];
|
26
16
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
const argsNode = path.getValue().body[0];
|
31
|
-
const hasBlock = argsNode.type === "args_add_block" && argsNode.body[1];
|
32
|
-
|
33
|
-
if (heredocs.length > 1) {
|
34
|
-
return concat(["(", join(", ", args), ")"].concat(heredocs));
|
35
|
-
}
|
17
|
+
if (argsNode === null) {
|
18
|
+
return "";
|
19
|
+
}
|
36
20
|
|
37
|
-
|
21
|
+
// Here we can skip the entire rest of the method by just checking if it's
|
22
|
+
// an args_forward node, as we're guaranteed that there are no other arg
|
23
|
+
// nodes.
|
24
|
+
if (argsNode.type === "args_forward") {
|
25
|
+
return group(
|
38
26
|
concat([
|
39
27
|
"(",
|
40
|
-
indent(
|
41
|
-
|
42
|
-
|
43
|
-
join(concat([",", line]), args),
|
44
|
-
addTrailingCommas && !hasBlock ? ifBreak(",", "") : ""
|
45
|
-
])
|
46
|
-
),
|
47
|
-
concat([softline, ")"])
|
28
|
+
indent(concat([softline, path.call(print, "body", 0)])),
|
29
|
+
softline,
|
30
|
+
")"
|
48
31
|
])
|
49
32
|
);
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
33
|
+
}
|
34
|
+
|
35
|
+
const args = path.call(print, "body", 0);
|
36
|
+
const hasBlock = argsNode.type === "args_add_block" && argsNode.body[1];
|
37
|
+
|
38
|
+
// Now here we return a doc that represents the whole grouped expression,
|
39
|
+
// including the surrouding parentheses.
|
40
|
+
return group(
|
41
|
+
concat([
|
42
|
+
"(",
|
43
|
+
indent(
|
44
|
+
concat([
|
45
|
+
softline,
|
46
|
+
join(concat([",", line]), args),
|
47
|
+
getTrailingComma(opts) && !hasBlock ? ifBreak(",", "") : ""
|
48
|
+
])
|
49
|
+
),
|
50
|
+
softline,
|
51
|
+
")"
|
52
|
+
])
|
53
|
+
);
|
54
|
+
}
|
55
|
+
|
56
|
+
function printArgs(path, { rubyToProc }, print) {
|
57
|
+
const args = path.map(print, "body");
|
58
|
+
|
59
|
+
// Don't bother trying to do any kind of fancy toProc transform if the
|
60
|
+
// option is disabled.
|
61
|
+
if (rubyToProc) {
|
59
62
|
let blockNode = null;
|
60
63
|
|
61
64
|
// Look up the chain to see if these arguments are contained within a
|
@@ -72,21 +75,26 @@ module.exports = {
|
|
72
75
|
return blockNode;
|
73
76
|
});
|
74
77
|
|
75
|
-
const proc = blockNode && toProc(path,
|
78
|
+
const proc = blockNode && toProc(path, blockNode);
|
76
79
|
|
77
|
-
// If we have a successful to_proc transformation, but we're part of an
|
78
|
-
// node, that means it's something to the effect of
|
80
|
+
// If we have a successful to_proc transformation, but we're part of an
|
81
|
+
// aref node, that means it's something to the effect of
|
79
82
|
//
|
80
83
|
// foo[:bar].each(&:to_s)
|
81
84
|
//
|
82
|
-
// In this case we need to just return regular arguments, otherwise we
|
83
|
-
// end up putting &:to_s inside the brackets accidentally.
|
85
|
+
// In this case we need to just return regular arguments, otherwise we
|
86
|
+
// would end up putting &:to_s inside the brackets accidentally.
|
84
87
|
if (proc && path.getParentNode(1).type !== "aref") {
|
85
88
|
args.push(proc);
|
86
89
|
}
|
90
|
+
}
|
87
91
|
|
88
|
-
|
89
|
-
|
92
|
+
return args;
|
93
|
+
}
|
94
|
+
|
95
|
+
module.exports = {
|
96
|
+
arg_paren: printArgParen,
|
97
|
+
args: printArgs,
|
90
98
|
args_add_block: (path, opts, print) => {
|
91
99
|
const parts = path.call(print, "body", 0);
|
92
100
|
|
data/src/nodes/arrays.js
CHANGED
@@ -1,55 +1,79 @@
|
|
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
|
-
const
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
12
|
+
const { getTrailingComma } = require("../utils");
|
13
|
+
|
14
|
+
// Checks that every argument within this args node is a string_literal node
|
15
|
+
// that has no spaces or interpolations. This means we're dealing with an array
|
16
|
+
// that looks something like:
|
17
|
+
//
|
18
|
+
// ['a', 'b', 'c']
|
19
|
+
//
|
20
|
+
function isStringArray(args) {
|
21
|
+
return (
|
22
|
+
args.body.length > 1 &&
|
23
|
+
args.body.every((arg) => {
|
24
|
+
// We want to verify that every node inside of this array is a string
|
25
|
+
// literal. We also want to make sure none of them have comments attached.
|
26
|
+
if (arg.type !== "string_literal" || arg.comments) {
|
27
|
+
return false;
|
28
|
+
}
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
// If the string has multiple parts (meaning plain string content but also
|
31
|
+
// interpolated content) then we know it's not a simple string.
|
32
|
+
if (arg.body.length !== 1) {
|
33
|
+
return false;
|
34
|
+
}
|
27
35
|
|
28
|
-
const
|
29
|
-
[start].concat(path.map(print, "body"));
|
36
|
+
const part = arg.body[0];
|
30
37
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
// If the only part of this string is not @tstring_content then it's
|
39
|
+
// interpolated, so again we can return false.
|
40
|
+
if (part.type !== "@tstring_content") {
|
41
|
+
return false;
|
42
|
+
}
|
35
43
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
indent(
|
42
|
-
concat([
|
43
|
-
softline,
|
44
|
-
join(concat([",", line]), path.call(print, "body", 1))
|
45
|
-
])
|
46
|
-
),
|
47
|
-
concat([softline, "]"])
|
48
|
-
])
|
44
|
+
// Finally, verify that the string doesn't contain a space, an escape
|
45
|
+
// character, or brackets so that we know it can be put into a string
|
46
|
+
// literal array.
|
47
|
+
return !/[\s\\[\]]/.test(part.body);
|
48
|
+
})
|
49
49
|
);
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
}
|
51
|
+
|
52
|
+
// Checks that every argument within this args node is a symbol_literal node (as
|
53
|
+
// opposed to a dyna_symbol) so it has no interpolation. This means we're
|
54
|
+
// dealing with an array that looks something like:
|
55
|
+
//
|
56
|
+
// [:a, :b, :c]
|
57
|
+
//
|
58
|
+
function isSymbolArray(args) {
|
59
|
+
return (
|
60
|
+
args.body.length > 1 &&
|
61
|
+
args.body.every((arg) => arg.type === "symbol_literal" && !arg.comments)
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
// Prints out a word that is a part of a special array literal that accepts
|
66
|
+
// interpolation. The body is an array of either plain strings or interpolated
|
67
|
+
// expressions.
|
68
|
+
function printSpecialArrayWord(path, opts, print) {
|
69
|
+
return concat(path.map(print, "body"));
|
70
|
+
}
|
71
|
+
|
72
|
+
// Prints out a special array literal. Accepts the parts of the array literal as
|
73
|
+
// an argument, where the first element of the parts array is a string that
|
74
|
+
// contains the special start.
|
75
|
+
function printSpecialArrayParts(parts) {
|
76
|
+
return group(
|
53
77
|
concat([
|
54
78
|
parts[0],
|
55
79
|
"[",
|
@@ -57,110 +81,99 @@ const printSpecialArray = (parts) =>
|
|
57
81
|
concat([softline, "]"])
|
58
82
|
])
|
59
83
|
);
|
84
|
+
}
|
85
|
+
|
86
|
+
// Generates a print function with an embedded special start character for the
|
87
|
+
// specific type of array literal that we're dealing with. The print function
|
88
|
+
// returns an array as it expects to eventually be handed off to
|
89
|
+
// printSpecialArrayParts.
|
90
|
+
function printSpecialArray(start) {
|
91
|
+
return function printSpecialArrayWithStart(path, opts, print) {
|
92
|
+
return [start].concat(path.map(print, "body"));
|
93
|
+
};
|
94
|
+
}
|
95
|
+
|
96
|
+
function printEmptyArrayWithComments(path, opts) {
|
97
|
+
const arrayNode = path.getValue();
|
98
|
+
|
99
|
+
const printComment = (commentPath, index) => {
|
100
|
+
arrayNode.comments[index].printed = true;
|
101
|
+
return opts.printer.printComment(commentPath);
|
102
|
+
};
|
103
|
+
|
104
|
+
return concat([
|
105
|
+
"[",
|
106
|
+
indent(
|
107
|
+
concat([hardline, join(hardline, path.map(printComment, "comments"))])
|
108
|
+
),
|
109
|
+
line,
|
110
|
+
"]"
|
111
|
+
]);
|
112
|
+
}
|
113
|
+
|
114
|
+
// An array node is any literal array in Ruby. This includes all of the special
|
115
|
+
// array literals as well as regular arrays. If it is a special array literal
|
116
|
+
// then it will have one child that represents the special array, otherwise it
|
117
|
+
// will have one child that contains all of the elements of the array.
|
118
|
+
function printArray(path, opts, print) {
|
119
|
+
const array = path.getValue();
|
120
|
+
const args = array.body[0];
|
121
|
+
|
122
|
+
// If there is no inner arguments node, then we're dealing with an empty
|
123
|
+
// array, so we can go ahead and return.
|
124
|
+
if (args === null) {
|
125
|
+
return array.comments ? printEmptyArrayWithComments(path, opts) : "[]";
|
126
|
+
}
|
60
127
|
|
61
|
-
//
|
62
|
-
//
|
63
|
-
|
64
|
-
const
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
128
|
+
// If we have an array that contains only simple string literals with no
|
129
|
+
// spaces or interpolation, then we're going to print a %w array.
|
130
|
+
if (opts.rubyArrayLiteral && isStringArray(args)) {
|
131
|
+
const printString = (stringPath) => stringPath.call(print, "body", 0);
|
132
|
+
const parts = path.map(printString, "body", 0, "body");
|
133
|
+
|
134
|
+
return printSpecialArrayParts(["%w"].concat(parts));
|
135
|
+
}
|
136
|
+
|
137
|
+
// If we have an array that contains only simple symbol literals with no
|
138
|
+
// interpolation, then we're going to print a %i array.
|
139
|
+
if (opts.rubyArrayLiteral && isSymbolArray(args)) {
|
140
|
+
const printSymbol = (symbolPath) => symbolPath.call(print, "body", 0);
|
141
|
+
const parts = path.map(printSymbol, "body", 0, "body");
|
142
|
+
|
143
|
+
return printSpecialArrayParts(["%i"].concat(parts));
|
70
144
|
}
|
71
145
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
146
|
+
// If we don't have a regular args node at this point then we have a special
|
147
|
+
// array literal. In that case we're going to print out the body (which will
|
148
|
+
// return to us an array with the first one being the start of the array) and
|
149
|
+
// send that over to the printSpecialArrayParts function.
|
150
|
+
if (!["args", "args_add_star"].includes(args.type)) {
|
151
|
+
return printSpecialArrayParts(path.call(print, "body", 0));
|
152
|
+
}
|
153
|
+
|
154
|
+
// Here we have a normal array of any type of object with no special literal
|
155
|
+
// types or anything.
|
156
|
+
return group(
|
157
|
+
concat([
|
158
|
+
"[",
|
159
|
+
indent(
|
160
|
+
concat([
|
161
|
+
softline,
|
162
|
+
join(concat([",", line]), path.call(print, "body", 0)),
|
163
|
+
getTrailingComma(opts) ? ifBreak(",", "") : ""
|
164
|
+
])
|
165
|
+
),
|
166
|
+
softline,
|
167
|
+
"]"
|
168
|
+
])
|
77
169
|
);
|
78
|
-
}
|
170
|
+
}
|
79
171
|
|
80
172
|
module.exports = {
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
},
|
88
|
-
aref_field: printAref,
|
89
|
-
array: (path, { addTrailingCommas }, print) => {
|
90
|
-
const args = path.getValue().body[0];
|
91
|
-
|
92
|
-
if (args === null) {
|
93
|
-
return "[]";
|
94
|
-
}
|
95
|
-
|
96
|
-
if (isStringArray(args)) {
|
97
|
-
return printSpecialArray(
|
98
|
-
["%w"].concat(getSpecialArrayParts(path, print, args))
|
99
|
-
);
|
100
|
-
}
|
101
|
-
|
102
|
-
if (isSymbolArray(args)) {
|
103
|
-
return printSpecialArray(
|
104
|
-
["%i"].concat(getSpecialArrayParts(path, print, args))
|
105
|
-
);
|
106
|
-
}
|
107
|
-
|
108
|
-
if (!["args", "args_add_star"].includes(args.type)) {
|
109
|
-
return printSpecialArray(path.call(print, "body", 0));
|
110
|
-
}
|
111
|
-
|
112
|
-
const normalDocs = [];
|
113
|
-
|
114
|
-
const elementDocs = path.call(print, "body", 0);
|
115
|
-
const elements = getElements(path.getValue().body[0], ["body", 0]);
|
116
|
-
|
117
|
-
// We need to manually loop through the elements in the array in order to
|
118
|
-
// take care of heredocs printing (their commas go after the opening, as
|
119
|
-
// opposed to at the end).
|
120
|
-
elements.forEach(({ element, elementPath }, index) => {
|
121
|
-
const isInner = index !== elements.length - 1;
|
122
|
-
|
123
|
-
const isStraightHeredoc = element.type === "heredoc";
|
124
|
-
const isSquigglyHeredoc =
|
125
|
-
element.type === "string_literal" && element.body[0].type === "heredoc";
|
126
|
-
|
127
|
-
if (isStraightHeredoc || isSquigglyHeredoc) {
|
128
|
-
const heredocNode = isStraightHeredoc ? element : element.body[0];
|
129
|
-
const heredocPath = [print].concat(elementPath);
|
130
|
-
|
131
|
-
if (isSquigglyHeredoc) {
|
132
|
-
heredocPath.push("body", 0);
|
133
|
-
}
|
134
|
-
|
135
|
-
normalDocs.push(
|
136
|
-
heredocNode.beging,
|
137
|
-
isInner || addTrailingCommas ? "," : "",
|
138
|
-
literalline,
|
139
|
-
concat(path.map.apply(path, heredocPath.concat("body"))),
|
140
|
-
heredocNode.ending,
|
141
|
-
isInner ? line : ""
|
142
|
-
);
|
143
|
-
} else {
|
144
|
-
normalDocs.push(elementDocs[index]);
|
145
|
-
|
146
|
-
if (isInner) {
|
147
|
-
normalDocs.push(concat([",", line]));
|
148
|
-
} else if (addTrailingCommas) {
|
149
|
-
normalDocs.push(ifBreak(",", ""));
|
150
|
-
}
|
151
|
-
}
|
152
|
-
});
|
153
|
-
|
154
|
-
return group(
|
155
|
-
concat([
|
156
|
-
"[",
|
157
|
-
indent(concat([softline].concat(normalDocs))),
|
158
|
-
concat([softline, "]"])
|
159
|
-
])
|
160
|
-
);
|
161
|
-
},
|
162
|
-
qsymbols: makeArray("%i"),
|
163
|
-
qwords: makeArray("%w"),
|
164
|
-
symbols: makeArray("%I"),
|
165
|
-
words: makeArray("%W")
|
173
|
+
array: printArray,
|
174
|
+
qsymbols: printSpecialArray("%i"),
|
175
|
+
qwords: printSpecialArray("%w"),
|
176
|
+
symbols: printSpecialArray("%I"),
|
177
|
+
word: printSpecialArrayWord,
|
178
|
+
words: printSpecialArray("%W")
|
166
179
|
};
|