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/src/nodes/conditionals.js
CHANGED
@@ -8,7 +8,9 @@ const {
|
|
8
8
|
indent,
|
9
9
|
softline
|
10
10
|
} = require("../prettier");
|
11
|
-
|
11
|
+
|
12
|
+
const { containsAssignment, isEmptyStmts } = require("../utils");
|
13
|
+
const inlineEnsureParens = require("../utils/inlineEnsureParens");
|
12
14
|
|
13
15
|
const printWithAddition = (keyword, path, print, { breaking = false } = {}) =>
|
14
16
|
concat([
|
@@ -78,52 +80,50 @@ const printTernary = (path, _opts, print) => {
|
|
78
80
|
// Prints an `if_mod` or `unless_mod` node. Because it was previously in the
|
79
81
|
// modifier form, we're guaranteed to not have an additional node, so we can
|
80
82
|
// just work with the predicate and the body.
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
concat([softline, "end"])
|
87
|
-
]);
|
83
|
+
function printSingle(keyword, modifier = false) {
|
84
|
+
return function printSingleWithKeyword(path, { rubyModifier }, print) {
|
85
|
+
const [_predicateNode, statementsNode] = path.getValue().body;
|
86
|
+
const predicateDoc = path.call(print, "body", 0);
|
87
|
+
const statementsDoc = path.call(print, "body", 1);
|
88
88
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
const multilineParts = [
|
90
|
+
`${keyword} `,
|
91
|
+
align(keyword.length + 1, predicateDoc),
|
92
|
+
indent(concat([softline, statementsDoc])),
|
93
|
+
softline,
|
94
|
+
"end"
|
95
|
+
];
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
+
// If we do not allow modifier form conditionals or there are comments
|
98
|
+
// inside of the body of the conditional, then we must print in the
|
99
|
+
// multiline form.
|
100
|
+
if (!rubyModifier || (!modifier && statementsNode.body[0].comments)) {
|
101
|
+
return concat([concat(multilineParts), breakParent]);
|
102
|
+
}
|
97
103
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
104
|
+
const inline = concat(
|
105
|
+
inlineEnsureParens(path, [
|
106
|
+
path.call(print, "body", 1),
|
107
|
+
` ${keyword} `,
|
108
|
+
path.call(print, "body", 0)
|
109
|
+
])
|
110
|
+
);
|
103
111
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
// will result in `{ key: nil }`. In this case what we need to do for the
|
114
|
-
// first expression to align is wrap it in parens, as in:
|
115
|
-
//
|
116
|
-
// hash[:key] = (:value if false)
|
117
|
-
if (["assign", "massign"].includes(path.getParentNode().type)) {
|
118
|
-
inlineParts = ["("].concat(inlineParts).concat(")");
|
119
|
-
}
|
112
|
+
// An expression with a conditional modifier (expression if true), the
|
113
|
+
// conditional body is parsed before the predicate expression, meaning that
|
114
|
+
// if the parser encountered a variable declaration, it would initialize
|
115
|
+
// that variable first before evaluating the predicate expression. That
|
116
|
+
// parse order means the difference between a NameError or not. #591
|
117
|
+
// https://docs.ruby-lang.org/en/2.0.0/syntax/control_expressions_rdoc.html#label-Modifier+if+and+unless
|
118
|
+
if (modifier && containsAssignment(statementsNode)) {
|
119
|
+
return inline;
|
120
|
+
}
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
}
|
122
|
+
return group(ifBreak(concat(multilineParts), inline));
|
123
|
+
};
|
124
|
+
}
|
124
125
|
|
125
126
|
const noTernary = [
|
126
|
-
"@comment",
|
127
127
|
"alias",
|
128
128
|
"assign",
|
129
129
|
"break",
|
@@ -180,7 +180,9 @@ const canTernary = (path) => {
|
|
180
180
|
const [predicate, stmts, addition] = path.getValue().body;
|
181
181
|
|
182
182
|
return (
|
183
|
-
!["assign", "opassign"].includes(
|
183
|
+
!["assign", "opassign", "command_call", "command"].includes(
|
184
|
+
predicate.type
|
185
|
+
) &&
|
184
186
|
addition &&
|
185
187
|
addition.type === "else" &&
|
186
188
|
[stmts, addition.body[0]].every(canTernaryStmts)
|
@@ -188,7 +190,7 @@ const canTernary = (path) => {
|
|
188
190
|
};
|
189
191
|
|
190
192
|
// A normalized print function for both `if` and `unless` nodes.
|
191
|
-
const printConditional = (keyword) => (path, {
|
193
|
+
const printConditional = (keyword) => (path, { rubyModifier }, print) => {
|
192
194
|
if (canTernary(path)) {
|
193
195
|
let ternaryParts = [path.call(print, "body", 0), " ? "].concat(
|
194
196
|
printTernaryClauses(
|
@@ -217,7 +219,7 @@ const printConditional = (keyword) => (path, { inlineConditionals }, print) => {
|
|
217
219
|
|
218
220
|
// If the body of the conditional is empty, then we explicitly have to use the
|
219
221
|
// block form.
|
220
|
-
if (statements
|
222
|
+
if (isEmptyStmts(statements) && !statements.body[0].comments) {
|
221
223
|
return concat([
|
222
224
|
`${keyword} `,
|
223
225
|
align(keyword.length + 1, path.call(print, "body", 0)),
|
@@ -237,7 +239,7 @@ const printConditional = (keyword) => (path, { inlineConditionals }, print) => {
|
|
237
239
|
]);
|
238
240
|
}
|
239
241
|
|
240
|
-
return printSingle(keyword)(path, {
|
242
|
+
return printSingle(keyword)(path, { rubyModifier }, print);
|
241
243
|
};
|
242
244
|
|
243
245
|
module.exports = {
|
@@ -272,7 +274,7 @@ module.exports = {
|
|
272
274
|
},
|
273
275
|
if: printConditional("if"),
|
274
276
|
ifop: printTernary,
|
275
|
-
if_mod: printSingle("if"),
|
277
|
+
if_mod: printSingle("if", true),
|
276
278
|
unless: printConditional("unless"),
|
277
|
-
unless_mod: printSingle("unless")
|
279
|
+
unless_mod: printSingle("unless", true)
|
278
280
|
};
|
data/src/nodes/constants.js
CHANGED
@@ -1,25 +1,43 @@
|
|
1
1
|
const { concat, group, indent, join, softline } = require("../prettier");
|
2
|
-
const {
|
2
|
+
const { makeCall } = require("../utils");
|
3
|
+
|
4
|
+
function printConstPath(path, opts, print) {
|
5
|
+
return join("::", path.map(print, "body"));
|
6
|
+
}
|
7
|
+
|
8
|
+
function printConstRef(path, opts, print) {
|
9
|
+
return path.call(print, "body", 0);
|
10
|
+
}
|
11
|
+
|
12
|
+
function printDefined(path, opts, print) {
|
13
|
+
return group(
|
14
|
+
concat([
|
15
|
+
"defined?(",
|
16
|
+
indent(concat([softline, path.call(print, "body", 0)])),
|
17
|
+
concat([softline, ")"])
|
18
|
+
])
|
19
|
+
);
|
20
|
+
}
|
21
|
+
|
22
|
+
function printField(path, opts, print) {
|
23
|
+
return group(
|
24
|
+
concat([
|
25
|
+
path.call(print, "body", 0),
|
26
|
+
concat([makeCall(path, opts, print), path.call(print, "body", 2)])
|
27
|
+
])
|
28
|
+
);
|
29
|
+
}
|
30
|
+
|
31
|
+
function printTopConst(path, opts, print) {
|
32
|
+
return concat(["::", path.call(print, "body", 0)]);
|
33
|
+
}
|
3
34
|
|
4
35
|
module.exports = {
|
5
|
-
const_path_field:
|
6
|
-
const_path_ref:
|
7
|
-
const_ref:
|
8
|
-
defined:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
indent(concat([softline, path.call(print, "body", 0)])),
|
13
|
-
concat([softline, ")"])
|
14
|
-
])
|
15
|
-
),
|
16
|
-
field: (path, opts, print) =>
|
17
|
-
group(
|
18
|
-
concat([
|
19
|
-
path.call(print, "body", 0),
|
20
|
-
concat([makeCall(path, opts, print), path.call(print, "body", 2)])
|
21
|
-
])
|
22
|
-
),
|
23
|
-
top_const_field: prefix("::"),
|
24
|
-
top_const_ref: prefix("::")
|
36
|
+
const_path_field: printConstPath,
|
37
|
+
const_path_ref: printConstPath,
|
38
|
+
const_ref: printConstRef,
|
39
|
+
defined: printDefined,
|
40
|
+
field: printField,
|
41
|
+
top_const_field: printTopConst,
|
42
|
+
top_const_ref: printTopConst
|
25
43
|
};
|
data/src/nodes/flow.js
CHANGED
@@ -1,6 +1,41 @@
|
|
1
1
|
const { concat, join } = require("../prettier");
|
2
2
|
const { literal } = require("../utils");
|
3
3
|
|
4
|
+
const nodeDive = (node, steps) => {
|
5
|
+
let current = node;
|
6
|
+
|
7
|
+
steps.forEach((step) => {
|
8
|
+
current = current[step];
|
9
|
+
});
|
10
|
+
|
11
|
+
return current;
|
12
|
+
};
|
13
|
+
|
14
|
+
const unskippableParens = [
|
15
|
+
"if_mod",
|
16
|
+
"rescue_mod",
|
17
|
+
"unless_mod",
|
18
|
+
"until_mod",
|
19
|
+
"while_mod"
|
20
|
+
];
|
21
|
+
|
22
|
+
const maybeHandleParens = (path, print, keyword, steps) => {
|
23
|
+
const node = nodeDive(path.getValue(), steps);
|
24
|
+
if (node.type !== "paren") {
|
25
|
+
return null;
|
26
|
+
}
|
27
|
+
|
28
|
+
const stmts = node.body[0].body;
|
29
|
+
if (stmts.length === 1 && !unskippableParens.includes(stmts[0].type)) {
|
30
|
+
return concat([
|
31
|
+
`${keyword} `,
|
32
|
+
path.call.apply(path, [print].concat(steps).concat("body", 0))
|
33
|
+
]);
|
34
|
+
}
|
35
|
+
|
36
|
+
return concat([keyword, path.call.apply(path, [print].concat(steps))]);
|
37
|
+
};
|
38
|
+
|
4
39
|
module.exports = {
|
5
40
|
break: (path, opts, print) => {
|
6
41
|
const content = path.getValue().body[0];
|
@@ -9,14 +44,11 @@ module.exports = {
|
|
9
44
|
return "break";
|
10
45
|
}
|
11
46
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
}
|
18
|
-
|
19
|
-
return concat(["break ", join(", ", path.call(print, "body", 0))]);
|
47
|
+
const steps = ["body", 0, "body", 0, "body", 0];
|
48
|
+
return (
|
49
|
+
maybeHandleParens(path, print, "break", steps) ||
|
50
|
+
concat(["break ", join(", ", path.call(print, "body", 0))])
|
51
|
+
);
|
20
52
|
},
|
21
53
|
next: (path, opts, print) => {
|
22
54
|
const args = path.getValue().body[0].body[0];
|
@@ -25,15 +57,11 @@ module.exports = {
|
|
25
57
|
return "next";
|
26
58
|
}
|
27
59
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
]);
|
34
|
-
}
|
35
|
-
|
36
|
-
return concat(["next ", join(", ", path.call(print, "body", 0))]);
|
60
|
+
const steps = ["body", 0, "body", 0, "body", 0];
|
61
|
+
return (
|
62
|
+
maybeHandleParens(path, print, "next", steps) ||
|
63
|
+
concat(["next ", join(", ", path.call(print, "body", 0))])
|
64
|
+
);
|
37
65
|
},
|
38
66
|
yield: (path, opts, print) => {
|
39
67
|
if (path.getValue().body[0].type === "paren") {
|
data/src/nodes/hashes.js
CHANGED
@@ -1,23 +1,14 @@
|
|
1
1
|
const {
|
2
2
|
concat,
|
3
3
|
group,
|
4
|
+
hardline,
|
4
5
|
ifBreak,
|
5
6
|
indent,
|
6
7
|
join,
|
7
|
-
line
|
8
|
-
literalline
|
8
|
+
line
|
9
9
|
} = require("../prettier");
|
10
|
-
const { prefix, skipAssignIndent } = require("../utils");
|
11
10
|
|
12
|
-
const
|
13
|
-
let current = node;
|
14
|
-
|
15
|
-
steps.forEach((step) => {
|
16
|
-
current = current[step];
|
17
|
-
});
|
18
|
-
|
19
|
-
return current;
|
20
|
-
};
|
11
|
+
const { getTrailingComma, prefix, skipAssignIndent } = require("../utils");
|
21
12
|
|
22
13
|
// When attempting to convert a hash rocket into a hash label, you need to take
|
23
14
|
// care because only certain patterns are allowed. Ruby source says that they
|
@@ -29,119 +20,142 @@ const nodeDive = (node, steps) => {
|
|
29
20
|
//
|
30
21
|
// This function represents that check, as it determines if it can convert the
|
31
22
|
// symbol node into a hash label.
|
32
|
-
|
33
|
-
const label = symbolLiteral.body[0].body
|
23
|
+
function isValidHashLabel(symbolLiteral) {
|
24
|
+
const label = symbolLiteral.body[0].body;
|
34
25
|
return label.match(/^[_A-Za-z]/) && !label.endsWith("=");
|
35
|
-
}
|
26
|
+
}
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
|
28
|
+
function canUseHashLabels(contentsNode) {
|
29
|
+
return contentsNode.body.every((assocNode) => {
|
30
|
+
if (assocNode.type === "assoc_splat") {
|
31
|
+
return true;
|
32
|
+
}
|
40
33
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
return concat([
|
52
|
-
path.call.apply(path, [print].concat(symbolSteps)),
|
53
|
-
":"
|
54
|
-
]);
|
55
|
-
}
|
56
|
-
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;
|
57
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), ":"]);
|
58
55
|
case "dyna_symbol":
|
59
|
-
|
60
|
-
return concat(labelDoc.parts.slice(1).concat(":"));
|
61
|
-
}
|
62
|
-
return concat([labelDoc, " =>"]);
|
63
|
-
default:
|
64
|
-
return concat([labelDoc, " =>"]);
|
56
|
+
return concat(print(path).parts.slice(1).concat(":"));
|
65
57
|
}
|
66
|
-
}
|
58
|
+
}
|
67
59
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
const parts = [makeLabel(path, opts, print, ["body", 0])];
|
72
|
-
|
73
|
-
if (skipAssignIndent(path.getValue().body[1])) {
|
74
|
-
parts.push(" ", valueDoc);
|
75
|
-
} else {
|
76
|
-
parts.push(indent(concat([line, valueDoc])));
|
77
|
-
}
|
60
|
+
function printHashKeyRocket(path, print) {
|
61
|
+
const node = path.getValue();
|
62
|
+
const doc = print(path);
|
78
63
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
assocDocs.push(
|
105
|
-
makeLabel(path, opts, print, ["body", 0, index, "body", 0]),
|
106
|
-
" ",
|
107
|
-
beging,
|
108
|
-
isInner || addTrailingCommas ? "," : "",
|
109
|
-
literalline,
|
110
|
-
concat(
|
111
|
-
path.map.apply(
|
112
|
-
path,
|
113
|
-
[print, "body", 0, index].concat(heredocSteps).concat("body")
|
114
|
-
)
|
115
|
-
),
|
116
|
-
ending,
|
117
|
-
isInner ? line : ""
|
118
|
-
);
|
119
|
-
} else {
|
120
|
-
assocDocs.push(path.call(print, "body", 0, index));
|
121
|
-
|
122
|
-
if (isInner) {
|
123
|
-
assocDocs.push(concat([",", line]));
|
124
|
-
} else if (addTrailingCommas) {
|
125
|
-
assocDocs.push(ifBreak(",", ""));
|
126
|
-
}
|
127
|
-
}
|
128
|
-
});
|
129
|
-
|
130
|
-
return group(concat(assocDocs));
|
131
|
-
},
|
132
|
-
bare_assoc_hash: (path, opts, print) =>
|
133
|
-
group(join(concat([",", line]), path.map(print, "body", 0))),
|
134
|
-
hash: (path, opts, print) => {
|
135
|
-
if (path.getValue().body[0] === null) {
|
136
|
-
return "{}";
|
137
|
-
}
|
64
|
+
if (node.type === "@label") {
|
65
|
+
return `:${doc.slice(0, doc.length - 1)} =>`;
|
66
|
+
}
|
67
|
+
|
68
|
+
return concat([doc, " =>"]);
|
69
|
+
}
|
70
|
+
|
71
|
+
function printAssocNew(path, opts, print) {
|
72
|
+
const { keyPrinter } = path.getParentNode();
|
73
|
+
|
74
|
+
const parts = [path.call((keyPath) => keyPrinter(keyPath, print), "body", 0)];
|
75
|
+
const valueDoc = path.call(print, "body", 1);
|
76
|
+
|
77
|
+
if (skipAssignIndent(path.getValue().body[1])) {
|
78
|
+
parts.push(" ", valueDoc);
|
79
|
+
} else {
|
80
|
+
parts.push(indent(concat([line, valueDoc])));
|
81
|
+
}
|
82
|
+
|
83
|
+
return group(concat(parts));
|
84
|
+
}
|
85
|
+
|
86
|
+
function printHashContents(path, opts, print) {
|
87
|
+
const node = path.getValue();
|
138
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") {
|
139
103
|
return group(
|
140
104
|
concat([
|
141
105
|
"{",
|
142
|
-
indent(
|
143
|
-
|
106
|
+
indent(
|
107
|
+
concat([
|
108
|
+
line,
|
109
|
+
contents,
|
110
|
+
getTrailingComma(opts) ? ifBreak(",", "") : ""
|
111
|
+
])
|
112
|
+
),
|
113
|
+
line,
|
114
|
+
"}"
|
144
115
|
])
|
145
116
|
);
|
146
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
|
+
|
124
|
+
function printEmptyHashWithComments(path, opts) {
|
125
|
+
const hashNode = path.getValue();
|
126
|
+
|
127
|
+
const printComment = (commentPath, index) => {
|
128
|
+
hashNode.comments[index].printed = true;
|
129
|
+
return opts.printer.printComment(commentPath);
|
130
|
+
};
|
131
|
+
|
132
|
+
return concat([
|
133
|
+
"{",
|
134
|
+
indent(
|
135
|
+
concat([hardline, join(hardline, path.map(printComment, "comments"))])
|
136
|
+
),
|
137
|
+
line,
|
138
|
+
"}"
|
139
|
+
]);
|
140
|
+
}
|
141
|
+
|
142
|
+
function printHash(path, opts, print) {
|
143
|
+
const hashNode = path.getValue();
|
144
|
+
|
145
|
+
// Hashes normally have a single assoclist_from_args child node. If it's
|
146
|
+
// missing, then it means we're dealing with an empty hash, so we can just
|
147
|
+
// exit here and print.
|
148
|
+
if (hashNode.body[0] === null) {
|
149
|
+
return hashNode.comments ? printEmptyHashWithComments(path, opts) : "{}";
|
150
|
+
}
|
151
|
+
|
152
|
+
return path.call(print, "body", 0);
|
153
|
+
}
|
154
|
+
|
155
|
+
module.exports = {
|
156
|
+
assoc_new: printAssocNew,
|
157
|
+
assoc_splat: prefix("**"),
|
158
|
+
assoclist_from_args: printHashContents,
|
159
|
+
bare_assoc_hash: printHashContents,
|
160
|
+
hash: printHash
|
147
161
|
};
|