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