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
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
|
};
|