prettier 1.0.0.pre.rc1 → 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 +14 -1
- data/README.md +11 -10
- data/package.json +1 -1
- data/src/embed.js +6 -2
- data/src/nodes/args.js +59 -78
- data/src/nodes/arrays.js +34 -30
- data/src/nodes/assign.js +2 -2
- data/src/nodes/calls.js +65 -45
- data/src/nodes/case.js +11 -7
- data/src/nodes/hashes.js +79 -39
- data/src/nodes/ints.js +0 -6
- data/src/nodes/lambdas.js +6 -22
- data/src/nodes/params.js +15 -3
- data/src/nodes/statements.js +33 -23
- data/src/parser.rb +18 -7
- data/src/ruby.js +11 -4
- data/src/toProc.js +2 -2
- data/src/utils.js +0 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 305f0248dc0f0b4ab56d698f04858e3d25df0f91888a203f75740ae5a06a7e0d
|
4
|
+
data.tar.gz: 192eaf1d3cd95a9dc3693c0346f636f53ae2baede4cd3de5d827bd671571daf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33a09aa76044b30dde5aa1555bfabc8f178607335ca0af9e4709d0f9fbfdc437c986097da85cc2d0c411326cb25d0672587a0253016bc89e71ca1245a5cfd652
|
7
|
+
data.tar.gz: b293f495c164808c4372dc79cfa801fd1603fe4907eafb374b61ba171cffbf1aaa09b6e0b1a427bc949099091db790a79d74d56c50f72c3ba006acc718b0065c
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [1.0.0-rc2] - 2020-12-10
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- [@kddeisz] - Print hashes with consistent keys (e.g., if one key cannot be a hash label, use all hash rockets).
|
14
|
+
- [@kddeisz] - Respect using `o` or not using `o` for octal numbers.
|
15
|
+
- [@kddeisz] - Ensure `when` clauses with multiple predicates that can be split into multiple lines are split correctly.
|
16
|
+
- [@kddeisz] - Ensure hash literal is split correctly when only its contents would fit on one line.
|
17
|
+
- [@kddeisz] - Simplify `toProc` checks by not calling if the option is disabled.
|
18
|
+
- [@johncsnyder], [@kddeisz] - Add `method_add_block` to the potential like of method calls that can be chained.
|
19
|
+
- [@kddeisz] - Add the `rubyArrayLiteral` option for disabling automatically turning into array literals.
|
20
|
+
|
9
21
|
## [1.0.0-rc1] - 2020-12-09
|
10
22
|
|
11
23
|
### Changed
|
@@ -928,7 +940,8 @@ would previously result in `array[]`, but now prints properly.
|
|
928
940
|
|
929
941
|
- Initial release 🎉
|
930
942
|
|
931
|
-
[unreleased]: https://github.com/prettier/plugin-ruby/compare/v1.0.0-
|
943
|
+
[unreleased]: https://github.com/prettier/plugin-ruby/compare/v1.0.0-rc2...HEAD
|
944
|
+
[1.0.0-rc2]: https://github.com/prettier/plugin-ruby/compare/v1.0.0-rc1...v1.0.0-rc2
|
932
945
|
[1.0.0-rc1]: https://github.com/prettier/plugin-ruby/compare/v0.22.0...v1.0.0-rc1
|
933
946
|
[0.22.0]: https://github.com/prettier/plugin-ruby/compare/v0.21.0...v0.22.0
|
934
947
|
[0.21.0]: https://github.com/prettier/plugin-ruby/compare/v0.20.1...v0.21.0
|
data/README.md
CHANGED
@@ -122,16 +122,17 @@ The `prettier` executable is now installed and ready for use:
|
|
122
122
|
|
123
123
|
Below are the options (from [`src/ruby.js`](src/ruby.js)) that `@prettier/plugin-ruby` currently supports:
|
124
124
|
|
125
|
-
| API Option
|
126
|
-
|
|
127
|
-
| `printWidth`
|
128
|
-
| `requirePragma`
|
129
|
-
| `
|
130
|
-
| `
|
131
|
-
| `
|
132
|
-
| `
|
133
|
-
| `
|
134
|
-
| `
|
125
|
+
| API Option | CLI Option | Default | Description |
|
126
|
+
| ------------------ | ---------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------------------ |
|
127
|
+
| `printWidth` | `--print-width` | `80` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#print-width)). |
|
128
|
+
| `requirePragma` | `--require-pragma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#require-pragma)). |
|
129
|
+
| `rubyArrayLiteral` | `--ruby-array-literal` | `true` | When possible, favor the use of string and symbol array literals. |
|
130
|
+
| `rubyHashLabel` | `--ruby-hash-label` | `true` | When possible, uses the shortened hash key syntax, as opposed to hash rockets. |
|
131
|
+
| `rubyModifier` | `--ruby-modifier` | `true` | When it fits on one line, allows while and until statements to use the modifier form. |
|
132
|
+
| `rubySingleQuote` | `--ruby-single-quote` | `true` | When double quotes are not necessary for interpolation, prefers the use of single quotes for string literals. |
|
133
|
+
| `rubyToProc` | `--ruby-to-proc` | `false` | When possible, convert blocks to the more concise `Symbol#to_proc` syntax. |
|
134
|
+
| `tabWidth` | `--tab-width` | `2` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#tab-width)). |
|
135
|
+
| `trailingComma` | `--trailing-comma` | `"es5"` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#trailing-comma)). `"es5"` is equivalent to `true`. |
|
135
136
|
|
136
137
|
Any of these can be added to your existing [prettier configuration
|
137
138
|
file](https://prettier.io/docs/en/configuration.html). For example:
|
data/package.json
CHANGED
data/src/embed.js
CHANGED
@@ -67,7 +67,11 @@ const embed = (path, print, textToDoc, _opts) => {
|
|
67
67
|
path.call(print, "beging"),
|
68
68
|
lineSuffix(
|
69
69
|
group(
|
70
|
-
concat([
|
70
|
+
concat([
|
71
|
+
indent(markAsRoot(formatted)),
|
72
|
+
literalLineNoBreak,
|
73
|
+
ending.trim()
|
74
|
+
])
|
71
75
|
)
|
72
76
|
)
|
73
77
|
]);
|
@@ -78,7 +82,7 @@ const embed = (path, print, textToDoc, _opts) => {
|
|
78
82
|
return markAsRoot(
|
79
83
|
concat([
|
80
84
|
path.call(print, "beging"),
|
81
|
-
lineSuffix(group(concat([formatted, literalLineNoBreak, ending])))
|
85
|
+
lineSuffix(group(concat([formatted, literalLineNoBreak, ending.trim()])))
|
82
86
|
])
|
83
87
|
);
|
84
88
|
};
|
data/src/nodes/args.js
CHANGED
@@ -9,80 +9,56 @@ const {
|
|
9
9
|
} = require("../prettier");
|
10
10
|
|
11
11
|
const toProc = require("../toProc");
|
12
|
-
const {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
12
|
+
const { getTrailingComma } = require("../utils");
|
13
|
+
|
14
|
+
function printArgParen(path, opts, print) {
|
15
|
+
const argsNode = path.getValue().body[0];
|
16
|
+
|
17
|
+
if (argsNode === null) {
|
18
|
+
return "";
|
19
|
+
}
|
20
|
+
|
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(
|
26
|
+
concat([
|
27
|
+
"(",
|
28
|
+
indent(concat([softline, path.call(print, "body", 0)])),
|
29
|
+
softline,
|
30
|
+
")"
|
31
|
+
])
|
32
|
+
);
|
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(
|
27
44
|
concat([
|
28
|
-
"(",
|
29
|
-
indent(concat([softline, path.call(print, "body", 0)])),
|
30
45
|
softline,
|
31
|
-
")
|
46
|
+
join(concat([",", line]), args),
|
47
|
+
getTrailingComma(opts) && !hasBlock ? ifBreak(",", "") : ""
|
32
48
|
])
|
33
|
-
)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
// Here we're going to make a determination on whether or not we should put
|
47
|
-
// a newline before the first argument. In some cases this makes the
|
48
|
-
// appearance a little better. For example, instead of taking this input:
|
49
|
-
//
|
50
|
-
// foo(arg1, arg2).bar(arg1, arg2).baz(arg1)
|
51
|
-
//
|
52
|
-
// and transforming it into this:
|
53
|
-
//
|
54
|
-
// foo(arg1, arg2).bar(arg1, arg2).baz(
|
55
|
-
// arg1
|
56
|
-
// )
|
57
|
-
//
|
58
|
-
// it instead gets transformed into this:
|
59
|
-
//
|
60
|
-
// foo(arg1, arg2).bar(arg1, arg2)
|
61
|
-
// .baz(arg1)
|
62
|
-
//
|
63
|
-
const maxDocLength = 15;
|
64
|
-
const firstArgDoc = args[0];
|
65
|
-
|
66
|
-
// prettier-ignore
|
67
|
-
const shouldWrapLine =
|
68
|
-
(args.reduce((sum, arg) => sum + docLength(arg), 0) > maxDocLength) ||
|
69
|
-
(args.length == 1 && firstArgDoc.type === "group" && docLength(firstArgDoc) > maxDocLength) ||
|
70
|
-
(firstArgDoc.type === "concat" && firstArgDoc.parts.some((part) => part.type === "group"));
|
71
|
-
|
72
|
-
// Here we're going to get all of the docs representing the doc that's
|
73
|
-
// inside the parentheses.
|
74
|
-
if (shouldWrapLine) {
|
75
|
-
argsDocs = [indent(concat([softline].concat(argsDocs))), softline];
|
76
|
-
} else {
|
77
|
-
argsDocs = [indent(concat(argsDocs))];
|
78
|
-
}
|
79
|
-
|
80
|
-
// Now here we return a doc that represents the whole grouped expression,
|
81
|
-
// including the surrouding parentheses.
|
82
|
-
return group(concat(["("].concat(argsDocs).concat(")")));
|
83
|
-
},
|
84
|
-
args: (path, opts, print) => {
|
85
|
-
const args = path.map(print, "body");
|
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) {
|
86
62
|
let blockNode = null;
|
87
63
|
|
88
64
|
// Look up the chain to see if these arguments are contained within a
|
@@ -99,21 +75,26 @@ module.exports = {
|
|
99
75
|
return blockNode;
|
100
76
|
});
|
101
77
|
|
102
|
-
const proc = blockNode && toProc(path,
|
78
|
+
const proc = blockNode && toProc(path, blockNode);
|
103
79
|
|
104
|
-
// If we have a successful to_proc transformation, but we're part of an
|
105
|
-
// 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
|
106
82
|
//
|
107
83
|
// foo[:bar].each(&:to_s)
|
108
84
|
//
|
109
|
-
// In this case we need to just return regular arguments, otherwise we
|
110
|
-
// 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.
|
111
87
|
if (proc && path.getParentNode(1).type !== "aref") {
|
112
88
|
args.push(proc);
|
113
89
|
}
|
90
|
+
}
|
114
91
|
|
115
|
-
|
116
|
-
|
92
|
+
return args;
|
93
|
+
}
|
94
|
+
|
95
|
+
module.exports = {
|
96
|
+
arg_paren: printArgParen,
|
97
|
+
args: printArgs,
|
117
98
|
args_add_block: (path, opts, print) => {
|
118
99
|
const parts = path.call(print, "body", 0);
|
119
100
|
|
data/src/nodes/arrays.js
CHANGED
@@ -18,32 +18,35 @@ const { getTrailingComma } = require("../utils");
|
|
18
18
|
// ['a', 'b', 'c']
|
19
19
|
//
|
20
20
|
function isStringArray(args) {
|
21
|
-
return
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
return false
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
+
}
|
29
|
+
|
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
|
+
}
|
35
|
+
|
36
|
+
const part = arg.body[0];
|
37
|
+
|
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
|
+
}
|
43
|
+
|
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
|
+
);
|
47
50
|
}
|
48
51
|
|
49
52
|
// Checks that every argument within this args node is a symbol_literal node (as
|
@@ -53,8 +56,9 @@ function isStringArray(args) {
|
|
53
56
|
// [:a, :b, :c]
|
54
57
|
//
|
55
58
|
function isSymbolArray(args) {
|
56
|
-
return
|
57
|
-
|
59
|
+
return (
|
60
|
+
args.body.length > 1 &&
|
61
|
+
args.body.every((arg) => arg.type === "symbol_literal" && !arg.comments)
|
58
62
|
);
|
59
63
|
}
|
60
64
|
|
@@ -123,7 +127,7 @@ function printArray(path, opts, print) {
|
|
123
127
|
|
124
128
|
// If we have an array that contains only simple string literals with no
|
125
129
|
// spaces or interpolation, then we're going to print a %w array.
|
126
|
-
if (isStringArray(args)) {
|
130
|
+
if (opts.rubyArrayLiteral && isStringArray(args)) {
|
127
131
|
const printString = (stringPath) => stringPath.call(print, "body", 0);
|
128
132
|
const parts = path.map(printString, "body", 0, "body");
|
129
133
|
|
@@ -132,7 +136,7 @@ function printArray(path, opts, print) {
|
|
132
136
|
|
133
137
|
// If we have an array that contains only simple symbol literals with no
|
134
138
|
// interpolation, then we're going to print a %i array.
|
135
|
-
if (isSymbolArray(args)) {
|
139
|
+
if (opts.rubyArrayLiteral && isSymbolArray(args)) {
|
136
140
|
const printSymbol = (symbolPath) => symbolPath.call(print, "body", 0);
|
137
141
|
const parts = path.map(printSymbol, "body", 0, "body");
|
138
142
|
|
data/src/nodes/assign.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
const { concat, group, indent, join, line } = require("../prettier");
|
2
|
-
const {
|
2
|
+
const { first, skipAssignIndent } = require("../utils");
|
3
3
|
|
4
4
|
function printAssign(path, opts, print) {
|
5
5
|
const [_targetNode, valueNode] = path.getValue().body;
|
@@ -34,6 +34,6 @@ function printOpAssign(path, opts, print) {
|
|
34
34
|
module.exports = {
|
35
35
|
assign: printAssign,
|
36
36
|
opassign: printOpAssign,
|
37
|
-
var_field:
|
37
|
+
var_field: first,
|
38
38
|
var_ref: first
|
39
39
|
};
|
data/src/nodes/calls.js
CHANGED
@@ -6,15 +6,15 @@ const {
|
|
6
6
|
indent,
|
7
7
|
softline
|
8
8
|
} = require("../prettier");
|
9
|
-
const {
|
9
|
+
const { first, makeCall, noIndent } = require("../utils");
|
10
10
|
|
11
11
|
const toProc = require("../toProc");
|
12
12
|
|
13
|
-
const chained = ["call", "method_add_arg"];
|
13
|
+
const chained = ["call", "method_add_arg", "method_add_block"];
|
14
14
|
|
15
15
|
function printCall(path, opts, print) {
|
16
|
-
const
|
17
|
-
const [receiverNode, _operatorNode, messageNode] =
|
16
|
+
const node = path.getValue();
|
17
|
+
const [receiverNode, _operatorNode, messageNode] = node.body;
|
18
18
|
|
19
19
|
const receiverDoc = path.call(print, "body", 0);
|
20
20
|
const operatorDoc = makeCall(path, opts, print);
|
@@ -24,21 +24,13 @@ function printCall(path, opts, print) {
|
|
24
24
|
// call syntax so if `call` is implicit, we don't print it out.
|
25
25
|
const messageDoc = messageNode === "call" ? "" : path.call(print, "body", 2);
|
26
26
|
|
27
|
-
// For certain left sides of the call nodes, we want to attach directly to
|
28
|
-
// the } or end.
|
29
|
-
if (noIndent.includes(receiverNode.type)) {
|
30
|
-
return concat([receiverDoc, operatorDoc, messageDoc]);
|
31
|
-
}
|
32
|
-
|
33
27
|
// The right side of the call node, as in everything including the operator
|
34
28
|
// and beyond.
|
35
|
-
const rightSideDoc =
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
])
|
41
|
-
);
|
29
|
+
const rightSideDoc = concat([
|
30
|
+
receiverNode.comments ? hardline : softline,
|
31
|
+
operatorDoc,
|
32
|
+
messageDoc
|
33
|
+
]);
|
42
34
|
|
43
35
|
// Get a reference to the parent node so we can check if we're inside a chain
|
44
36
|
const parentNode = path.getParentNode();
|
@@ -46,27 +38,31 @@ function printCall(path, opts, print) {
|
|
46
38
|
// If our parent node is a chained node then we're not going to group the
|
47
39
|
// right side of the expression, as we want to have a nice multi-line layout.
|
48
40
|
if (chained.includes(parentNode.type)) {
|
49
|
-
parentNode.chain = (
|
50
|
-
parentNode.breakDoc = (
|
51
|
-
rightSideDoc
|
52
|
-
);
|
41
|
+
parentNode.chain = (node.chain || 0) + 1;
|
42
|
+
parentNode.breakDoc = (node.breakDoc || [receiverDoc]).concat(rightSideDoc);
|
53
43
|
}
|
54
44
|
|
55
45
|
// If we're at the top of a chain, then we're going to print out a nice
|
56
46
|
// multi-line layout if this doesn't break into multiple lines.
|
57
|
-
if (!chained.includes(parentNode.type) && (
|
47
|
+
if (!chained.includes(parentNode.type) && (node.chain || 0) >= 3) {
|
58
48
|
return ifBreak(
|
59
|
-
group(concat(
|
49
|
+
group(indent(concat(node.breakDoc.concat(rightSideDoc)))),
|
60
50
|
concat([receiverDoc, group(rightSideDoc)])
|
61
51
|
);
|
62
52
|
}
|
63
53
|
|
64
|
-
|
54
|
+
// For certain left sides of the call nodes, we want to attach directly to
|
55
|
+
// the } or end.
|
56
|
+
if (noIndent.includes(receiverNode.type)) {
|
57
|
+
return concat([receiverDoc, operatorDoc, messageDoc]);
|
58
|
+
}
|
59
|
+
|
60
|
+
return group(concat([receiverDoc, group(indent(rightSideDoc))]));
|
65
61
|
}
|
66
62
|
|
67
63
|
function printMethodAddArg(path, opts, print) {
|
68
|
-
const
|
69
|
-
const argNode =
|
64
|
+
const node = path.getValue();
|
65
|
+
const argNode = node.body[1];
|
70
66
|
|
71
67
|
const [methodDoc, argsDoc] = path.map(print, "body");
|
72
68
|
|
@@ -88,20 +84,15 @@ function printMethodAddArg(path, opts, print) {
|
|
88
84
|
// If our parent node is a chained node then we're not going to group the
|
89
85
|
// right side of the expression, as we want to have a nice multi-line layout.
|
90
86
|
if (chained.includes(parentNode.type)) {
|
91
|
-
parentNode.chain = (
|
92
|
-
parentNode.breakDoc = (
|
93
|
-
argsDoc
|
94
|
-
);
|
87
|
+
parentNode.chain = (node.chain || 0) + 1;
|
88
|
+
parentNode.breakDoc = (node.breakDoc || [methodDoc]).concat(argsDoc);
|
95
89
|
}
|
96
90
|
|
97
91
|
// If we're at the top of a chain, then we're going to print out a nice
|
98
92
|
// multi-line layout if this doesn't break into multiple lines.
|
99
|
-
if (
|
100
|
-
!chained.includes(parentNode.type) &&
|
101
|
-
(methodAddArgNode.chain || 0) >= 3
|
102
|
-
) {
|
93
|
+
if (!chained.includes(parentNode.type) && (node.chain || 0) >= 3) {
|
103
94
|
return ifBreak(
|
104
|
-
group(concat(
|
95
|
+
group(indent(concat(node.breakDoc.concat(argsDoc)))),
|
105
96
|
concat([methodDoc, argsDoc])
|
106
97
|
);
|
107
98
|
}
|
@@ -109,15 +100,18 @@ function printMethodAddArg(path, opts, print) {
|
|
109
100
|
return concat([methodDoc, argsDoc]);
|
110
101
|
}
|
111
102
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
const [method, block] = path.getValue().body;
|
118
|
-
const proc = toProc(path, opts, block);
|
103
|
+
function printMethodAddBlock(path, { rubyToProc }, print) {
|
104
|
+
const node = path.getValue();
|
105
|
+
|
106
|
+
const [callNode, blockNode] = node.body;
|
107
|
+
const [callDoc, blockDoc] = path.map(print, "body");
|
119
108
|
|
120
|
-
|
109
|
+
// Don't bother trying to do any kind of fancy toProc transform if the option
|
110
|
+
// is disabled.
|
111
|
+
if (rubyToProc) {
|
112
|
+
const proc = toProc(path, blockNode);
|
113
|
+
|
114
|
+
if (proc && callNode.type === "call") {
|
121
115
|
return group(
|
122
116
|
concat([
|
123
117
|
path.call(print, "body", 0),
|
@@ -131,8 +125,34 @@ module.exports = {
|
|
131
125
|
if (proc) {
|
132
126
|
return path.call(print, "body", 0);
|
133
127
|
}
|
128
|
+
}
|
134
129
|
|
135
|
-
|
136
|
-
|
130
|
+
// Get a reference to the parent node so we can check if we're inside a chain
|
131
|
+
const parentNode = path.getParentNode();
|
132
|
+
|
133
|
+
// If our parent node is a chained node then we're not going to group the
|
134
|
+
// right side of the expression, as we want to have a nice multi-line layout.
|
135
|
+
if (chained.includes(parentNode.type)) {
|
136
|
+
parentNode.chain = (node.chain || 0) + 1;
|
137
|
+
parentNode.breakDoc = (node.breakDoc || [callDoc]).concat(blockDoc);
|
138
|
+
}
|
139
|
+
|
140
|
+
// If we're at the top of a chain, then we're going to print out a nice
|
141
|
+
// multi-line layout if this doesn't break into multiple lines.
|
142
|
+
if (!chained.includes(parentNode.type) && (node.chain || 0) >= 3) {
|
143
|
+
return ifBreak(
|
144
|
+
group(indent(concat(node.breakDoc.concat(blockDoc)))),
|
145
|
+
concat([callDoc, blockDoc])
|
146
|
+
);
|
147
|
+
}
|
148
|
+
|
149
|
+
return concat([callDoc, blockDoc]);
|
150
|
+
}
|
151
|
+
|
152
|
+
module.exports = {
|
153
|
+
call: printCall,
|
154
|
+
fcall: first,
|
155
|
+
method_add_arg: printMethodAddArg,
|
156
|
+
method_add_block: printMethodAddBlock,
|
137
157
|
vcall: first
|
138
158
|
};
|
data/src/nodes/case.js
CHANGED
@@ -28,13 +28,17 @@ module.exports = {
|
|
28
28
|
// The `fill` builder command expects an array of docs alternating with
|
29
29
|
// line breaks. This is so it can loop through and determine where to break.
|
30
30
|
const preds = fill(
|
31
|
-
path
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
path.call(print, "body", 0).reduce((accum, pred, index) => {
|
32
|
+
if (index === 0) {
|
33
|
+
return [pred];
|
34
|
+
}
|
35
|
+
|
36
|
+
// Pull off the last element and make it concat with a comma so that
|
37
|
+
// we can maintain alternating lines and docs.
|
38
|
+
return accum
|
39
|
+
.slice(0, -1)
|
40
|
+
.concat([concat([accum[accum.length - 1], ","]), line, pred]);
|
41
|
+
}, null)
|
38
42
|
);
|
39
43
|
|
40
44
|
const stmts = path.call(print, "body", 1);
|
data/src/nodes/hashes.js
CHANGED
@@ -25,35 +25,54 @@ function isValidHashLabel(symbolLiteral) {
|
|
25
25
|
return label.match(/^[_A-Za-z]/) && !label.endsWith("=");
|
26
26
|
}
|
27
27
|
|
28
|
-
function
|
29
|
-
|
30
|
-
|
28
|
+
function canUseHashLabels(contentsNode) {
|
29
|
+
return contentsNode.body.every((assocNode) => {
|
30
|
+
if (assocNode.type === "assoc_splat") {
|
31
|
+
return true;
|
32
|
+
}
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
return
|
41
|
-
}
|
42
|
-
return concat([labelDoc, " =>"]);
|
34
|
+
switch (assocNode.body[0].type) {
|
35
|
+
case "@label":
|
36
|
+
return true;
|
37
|
+
case "symbol_literal":
|
38
|
+
return isValidHashLabel(assocNode.body[0]);
|
39
|
+
case "dyna_symbol":
|
40
|
+
return true;
|
41
|
+
default:
|
42
|
+
return false;
|
43
43
|
}
|
44
|
+
});
|
45
|
+
}
|
46
|
+
|
47
|
+
function printHashKeyLabel(path, print) {
|
48
|
+
const node = path.getValue();
|
49
|
+
|
50
|
+
switch (node.type) {
|
51
|
+
case "@label":
|
52
|
+
return print(path);
|
53
|
+
case "symbol_literal":
|
54
|
+
return concat([path.call(print, "body", 0), ":"]);
|
44
55
|
case "dyna_symbol":
|
45
|
-
|
46
|
-
return concat(labelDoc.parts.slice(1).concat(":"));
|
47
|
-
}
|
48
|
-
return concat([labelDoc, " =>"]);
|
49
|
-
default:
|
50
|
-
return concat([labelDoc, " =>"]);
|
56
|
+
return concat(print(path).parts.slice(1).concat(":"));
|
51
57
|
}
|
52
58
|
}
|
53
59
|
|
60
|
+
function printHashKeyRocket(path, print) {
|
61
|
+
const node = path.getValue();
|
62
|
+
const doc = print(path);
|
63
|
+
|
64
|
+
if (node.type === "@label") {
|
65
|
+
return `:${doc.slice(0, doc.length - 1)} =>`;
|
66
|
+
}
|
67
|
+
|
68
|
+
return concat([doc, " =>"]);
|
69
|
+
}
|
70
|
+
|
54
71
|
function printAssocNew(path, opts, print) {
|
72
|
+
const { keyPrinter } = path.getParentNode();
|
73
|
+
|
74
|
+
const parts = [path.call((keyPath) => keyPrinter(keyPath, print), "body", 0)];
|
55
75
|
const valueDoc = path.call(print, "body", 1);
|
56
|
-
const parts = [printHashKey(path, opts, print)];
|
57
76
|
|
58
77
|
if (skipAssignIndent(path.getValue().body[1])) {
|
59
78
|
parts.push(" ", valueDoc);
|
@@ -64,6 +83,44 @@ function printAssocNew(path, opts, print) {
|
|
64
83
|
return group(concat(parts));
|
65
84
|
}
|
66
85
|
|
86
|
+
function printHashContents(path, opts, print) {
|
87
|
+
const node = path.getValue();
|
88
|
+
|
89
|
+
// First determine which key printer we're going to use, so that the child
|
90
|
+
// nodes can reference it when they go to get printed.
|
91
|
+
node.keyPrinter =
|
92
|
+
opts.rubyHashLabel && canUseHashLabels(path.getValue())
|
93
|
+
? printHashKeyLabel
|
94
|
+
: printHashKeyRocket;
|
95
|
+
|
96
|
+
const contents = join(concat([",", line]), path.map(print, "body"));
|
97
|
+
|
98
|
+
// If we're inside a hash literal, then we want to add the braces at this
|
99
|
+
// level so that the grouping is correct. Otherwise you could end up with
|
100
|
+
// opening and closing braces being split up, but the contents not being split
|
101
|
+
// correctly.
|
102
|
+
if (path.getParentNode().type === "hash") {
|
103
|
+
return group(
|
104
|
+
concat([
|
105
|
+
"{",
|
106
|
+
indent(
|
107
|
+
concat([
|
108
|
+
line,
|
109
|
+
contents,
|
110
|
+
getTrailingComma(opts) ? ifBreak(",", "") : ""
|
111
|
+
])
|
112
|
+
),
|
113
|
+
line,
|
114
|
+
"}"
|
115
|
+
])
|
116
|
+
);
|
117
|
+
}
|
118
|
+
|
119
|
+
// Otherwise, we're inside a bare_assoc_hash, so we don't want to print
|
120
|
+
// braces at all.
|
121
|
+
return group(contents);
|
122
|
+
}
|
123
|
+
|
67
124
|
function printEmptyHashWithComments(path, opts) {
|
68
125
|
const hashNode = path.getValue();
|
69
126
|
|
@@ -92,24 +149,7 @@ function printHash(path, opts, print) {
|
|
92
149
|
return hashNode.comments ? printEmptyHashWithComments(path, opts) : "{}";
|
93
150
|
}
|
94
151
|
|
95
|
-
return
|
96
|
-
concat([
|
97
|
-
"{",
|
98
|
-
indent(
|
99
|
-
concat([
|
100
|
-
line,
|
101
|
-
path.call(print, "body", 0),
|
102
|
-
getTrailingComma(opts) ? ifBreak(",", "") : ""
|
103
|
-
])
|
104
|
-
),
|
105
|
-
line,
|
106
|
-
"}"
|
107
|
-
])
|
108
|
-
);
|
109
|
-
}
|
110
|
-
|
111
|
-
function printHashContents(path, opts, print) {
|
112
|
-
return group(join(concat([",", line]), path.map(print, "body")));
|
152
|
+
return path.call(print, "body", 0);
|
113
153
|
}
|
114
154
|
|
115
155
|
module.exports = {
|
data/src/nodes/ints.js
CHANGED
@@ -12,12 +12,6 @@
|
|
12
12
|
function printInt(path, _opts, _print) {
|
13
13
|
const { body } = path.getValue();
|
14
14
|
|
15
|
-
// If the number is octal and does not contain the optional "o" character
|
16
|
-
// after the leading 0, add it in.
|
17
|
-
if (/^0[0-9]/.test(body)) {
|
18
|
-
return `0o${body.slice(1)}`;
|
19
|
-
}
|
20
|
-
|
21
15
|
// If the number is a base 10 number, is sufficiently large, and is not
|
22
16
|
// already formatted with underscores, then add them in in between the
|
23
17
|
// numbers every three characters starting from the right.
|
data/src/nodes/lambdas.js
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
const {
|
2
|
-
concat,
|
3
|
-
group,
|
4
|
-
ifBreak,
|
5
|
-
indent,
|
6
|
-
line,
|
7
|
-
softline
|
8
|
-
} = require("../prettier");
|
1
|
+
const { concat, group, ifBreak, indent, line } = require("../prettier");
|
9
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,
|
@@ -13,31 +6,22 @@ const { hasAncestor } = require("../utils");
|
|
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
8
|
function printLambdaParams(path, print) {
|
16
|
-
|
17
|
-
let paramsNode = path.getValue().body[0];
|
9
|
+
let node = path.getValue().body[0];
|
18
10
|
|
19
11
|
// In this case we had something like -> (foo) { bar } which would mean that
|
20
12
|
// we're looking at a paren node, so we'll descend one level deeper to get at
|
21
13
|
// the actual params node.
|
22
|
-
if (
|
23
|
-
|
24
|
-
paramsNode = paramsNode.body[0];
|
14
|
+
if (node.type !== "params") {
|
15
|
+
node = node.body[0];
|
25
16
|
}
|
26
17
|
|
27
18
|
// If we don't have any params at all, then we're just going to bail out and
|
28
19
|
// print nothing. This is to avoid printing an empty set of parentheses.
|
29
|
-
if (
|
20
|
+
if (node.body.every((type) => !type)) {
|
30
21
|
return "";
|
31
22
|
}
|
32
23
|
|
33
|
-
return
|
34
|
-
concat([
|
35
|
-
"(",
|
36
|
-
indent(concat([softline, path.call.apply(path, paramsPath)])),
|
37
|
-
softline,
|
38
|
-
")"
|
39
|
-
])
|
40
|
-
);
|
24
|
+
return path.call(print, "body", 0);
|
41
25
|
}
|
42
26
|
|
43
27
|
// Lambda nodes represent stabby lambda literals, which can come in a couple of
|
data/src/nodes/params.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
const { concat, group, join, line } = require("../prettier");
|
1
|
+
const { concat, group, join, indent, line, softline } = require("../prettier");
|
2
2
|
const { literal } = require("../utils");
|
3
3
|
|
4
4
|
function printRestParam(symbol) {
|
@@ -64,6 +64,8 @@ function printParams(path, opts, print) {
|
|
64
64
|
parts.push(path.call(print, "body", 6));
|
65
65
|
}
|
66
66
|
|
67
|
+
const contents = [join(concat([",", line]), parts)];
|
68
|
+
|
67
69
|
// You can put an extra comma at the end of block args between pipes to
|
68
70
|
// change what it does. Below is the difference:
|
69
71
|
//
|
@@ -73,9 +75,19 @@ function printParams(path, opts, print) {
|
|
73
75
|
// In ruby 2.5, the excessed comma is indicated by having a 0 in the rest
|
74
76
|
// param position. In ruby 2.6+ it's indicated by having an "excessed_comma"
|
75
77
|
// node in the rest position. Seems odd, but it's true.
|
76
|
-
|
78
|
+
if (rest === 0 || (rest && rest.type === "excessed_comma")) {
|
79
|
+
contents.push(",");
|
80
|
+
}
|
81
|
+
|
82
|
+
// If the parent node is a paren then we skipped printing the parentheses so
|
83
|
+
// that we could handle them here and get nicer formatting.
|
84
|
+
if (["lambda", "paren"].includes(path.getParentNode().type)) {
|
85
|
+
return group(
|
86
|
+
concat(["(", indent(concat([softline].concat(contents))), softline, ")"])
|
87
|
+
);
|
88
|
+
}
|
77
89
|
|
78
|
-
return group(concat(
|
90
|
+
return group(concat(contents));
|
79
91
|
}
|
80
92
|
|
81
93
|
module.exports = {
|
data/src/nodes/statements.js
CHANGED
@@ -45,35 +45,45 @@ function printBodyStmt(path, opts, print) {
|
|
45
45
|
return group(concat(parts));
|
46
46
|
}
|
47
47
|
|
48
|
+
const argNodeTypes = ["args", "args_add_star", "args_add_block"];
|
49
|
+
|
50
|
+
function printParen(path, opts, print) {
|
51
|
+
const contentNode = path.getValue().body[0];
|
52
|
+
|
53
|
+
if (!contentNode) {
|
54
|
+
return "()";
|
55
|
+
}
|
56
|
+
|
57
|
+
let contentDoc = path.call(print, "body", 0);
|
58
|
+
|
59
|
+
// If the content is params, we're going to let it handle its own parentheses
|
60
|
+
// so that it breaks nicely.
|
61
|
+
if (contentNode.type === "params") {
|
62
|
+
return contentDoc;
|
63
|
+
}
|
64
|
+
|
65
|
+
// If we have an arg type node as the contents, then it's going to return an
|
66
|
+
// array, so we need to explicitly join that content here.
|
67
|
+
if (argNodeTypes.includes(contentNode.type)) {
|
68
|
+
contentDoc = join(concat([",", line]), contentDoc);
|
69
|
+
}
|
70
|
+
|
71
|
+
return group(
|
72
|
+
concat([
|
73
|
+
"(",
|
74
|
+
indent(concat([softline, contentDoc])),
|
75
|
+
concat([softline, ")"])
|
76
|
+
])
|
77
|
+
);
|
78
|
+
}
|
79
|
+
|
48
80
|
module.exports = {
|
49
81
|
"@__end__": (path, _opts, _print) => {
|
50
82
|
const { body } = path.getValue();
|
51
83
|
return concat([trim, "__END__", literalline, body]);
|
52
84
|
},
|
53
85
|
bodystmt: printBodyStmt,
|
54
|
-
paren:
|
55
|
-
if (!path.getValue().body[0]) {
|
56
|
-
return "()";
|
57
|
-
}
|
58
|
-
|
59
|
-
let content = path.call(print, "body", 0);
|
60
|
-
|
61
|
-
if (
|
62
|
-
["args", "args_add_star", "args_add_block"].includes(
|
63
|
-
path.getValue().body[0].type
|
64
|
-
)
|
65
|
-
) {
|
66
|
-
content = join(concat([",", line]), content);
|
67
|
-
}
|
68
|
-
|
69
|
-
return group(
|
70
|
-
concat([
|
71
|
-
"(",
|
72
|
-
indent(concat([softline, content])),
|
73
|
-
concat([softline, ")"])
|
74
|
-
])
|
75
|
-
);
|
76
|
-
},
|
86
|
+
paren: printParen,
|
77
87
|
program: (path, opts, print) =>
|
78
88
|
concat([join(hardline, path.map(print, "body")), hardline]),
|
79
89
|
stmts: (path, opts, print) => {
|
data/src/parser.rb
CHANGED
@@ -566,8 +566,10 @@ class Prettier::Parser < Ripper
|
|
566
566
|
|
567
567
|
# Here we're going to determine the bounds for the stmts
|
568
568
|
consequent = parts[1..-1].compact.first
|
569
|
-
self[:body][0].bind(
|
570
|
-
|
569
|
+
self[:body][0].bind(
|
570
|
+
char_start,
|
571
|
+
consequent ? consequent[:char_start] : char_end
|
572
|
+
)
|
571
573
|
|
572
574
|
# Next we're going to determine the rescue clause if there is one
|
573
575
|
if parts[1]
|
@@ -1064,7 +1066,10 @@ class Prettier::Parser < Ripper
|
|
1064
1066
|
# event, so here we'll initialize the current embdoc.
|
1065
1067
|
def on_embdoc_beg(value)
|
1066
1068
|
@embdoc = {
|
1067
|
-
type: :@embdoc,
|
1069
|
+
type: :@embdoc,
|
1070
|
+
value: value,
|
1071
|
+
start: lineno,
|
1072
|
+
char_start: char_pos
|
1068
1073
|
}
|
1069
1074
|
end
|
1070
1075
|
|
@@ -1211,9 +1216,12 @@ class Prettier::Parser < Ripper
|
|
1211
1216
|
|
1212
1217
|
# Here we're going to artificially create an extra node type so that if
|
1213
1218
|
# there are comments after the declaration of a heredoc, they get printed.
|
1214
|
-
location
|
1215
|
-
|
1216
|
-
|
1219
|
+
location
|
1220
|
+
.merge(
|
1221
|
+
type: :heredoc,
|
1222
|
+
beging: location.merge(type: :@heredoc_beg, body: beging)
|
1223
|
+
)
|
1224
|
+
.tap { |node| @heredocs << node }
|
1217
1225
|
end
|
1218
1226
|
|
1219
1227
|
# This is a parser event that occurs when you're using a heredoc with a
|
@@ -1644,7 +1652,10 @@ class Prettier::Parser < Ripper
|
|
1644
1652
|
# some found at the end of the source string.
|
1645
1653
|
def on_program(stmts)
|
1646
1654
|
range = {
|
1647
|
-
start: 1,
|
1655
|
+
start: 1,
|
1656
|
+
end: lines.length,
|
1657
|
+
char_start: 0,
|
1658
|
+
char_end: source.length
|
1648
1659
|
}
|
1649
1660
|
|
1650
1661
|
stmts[:body] << @__end__ if @__end__
|
data/src/ruby.js
CHANGED
@@ -76,30 +76,37 @@ module.exports = {
|
|
76
76
|
ruby: printer
|
77
77
|
},
|
78
78
|
options: {
|
79
|
+
rubyArrayLiteral: {
|
80
|
+
type: "boolean",
|
81
|
+
category: "Ruby",
|
82
|
+
default: true,
|
83
|
+
description:
|
84
|
+
"When possible, favor the use of string and symbol array literals."
|
85
|
+
},
|
79
86
|
rubyHashLabel: {
|
80
87
|
type: "boolean",
|
81
|
-
category: "
|
88
|
+
category: "Ruby",
|
82
89
|
default: true,
|
83
90
|
description:
|
84
91
|
"When possible, uses the shortened hash key syntax, as opposed to hash rockets."
|
85
92
|
},
|
86
93
|
rubyModifier: {
|
87
94
|
type: "boolean",
|
88
|
-
category: "
|
95
|
+
category: "Ruby",
|
89
96
|
default: true,
|
90
97
|
description:
|
91
98
|
"When it fits on one line, allows if, unless, while, and until statements to use the modifier form."
|
92
99
|
},
|
93
100
|
rubySingleQuote: {
|
94
101
|
type: "boolean",
|
95
|
-
category: "
|
102
|
+
category: "Ruby",
|
96
103
|
default: true,
|
97
104
|
description:
|
98
105
|
"When double quotes are not necessary for interpolation, prefers the use of single quotes for string literals."
|
99
106
|
},
|
100
107
|
rubyToProc: {
|
101
108
|
type: "boolean",
|
102
|
-
category: "
|
109
|
+
category: "Ruby",
|
103
110
|
default: false,
|
104
111
|
description:
|
105
112
|
"When possible, convert blocks to the more concise Symbol#to_proc syntax."
|
data/src/toProc.js
CHANGED
@@ -11,8 +11,8 @@ const isCall = (node) => ["::", "."].includes(node) || node.type === "@period";
|
|
11
11
|
// [1, 2, 3].map(&:to_s)
|
12
12
|
//
|
13
13
|
// This works with `do` blocks as well.
|
14
|
-
const toProc = (path,
|
15
|
-
if (!node
|
14
|
+
const toProc = (path, node) => {
|
15
|
+
if (!node) {
|
16
16
|
return null;
|
17
17
|
}
|
18
18
|
|
data/src/utils.js
CHANGED
@@ -2,8 +2,6 @@ const { concat } = require("./prettier");
|
|
2
2
|
const isEmptyStmts = require("./utils/isEmptyStmts");
|
3
3
|
const literalLineNoBreak = require("./utils/literalLineNoBreak");
|
4
4
|
|
5
|
-
const concatBody = (path, opts, print) => concat(path.map(print, "body"));
|
6
|
-
|
7
5
|
// If the node is a type of assignment or if the node is a paren and nested
|
8
6
|
// inside that paren is a node that is a type of assignment.
|
9
7
|
const containsAssignment = (node) =>
|
@@ -79,7 +77,6 @@ const skipAssignIndent = (node) =>
|
|
79
77
|
(node.type === "call" && skipAssignIndent(node.body[0]));
|
80
78
|
|
81
79
|
module.exports = {
|
82
|
-
concatBody,
|
83
80
|
containsAssignment,
|
84
81
|
docLength,
|
85
82
|
empty,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prettier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.
|
4
|
+
version: 1.0.0.pre.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Deisz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|