prettier 1.5.5 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +31 -12
- data/node_modules/prettier/bin-prettier.js +13702 -11629
- data/node_modules/prettier/index.js +19198 -16572
- data/node_modules/prettier/parser-angular.js +61 -40
- data/node_modules/prettier/parser-babel.js +22 -1
- data/node_modules/prettier/parser-espree.js +22 -1
- data/node_modules/prettier/parser-flow.js +22 -1
- data/node_modules/prettier/parser-glimmer.js +1 -1
- data/node_modules/prettier/parser-graphql.js +1 -1
- data/node_modules/prettier/parser-html.js +82 -63
- data/node_modules/prettier/parser-markdown.js +24 -9
- data/node_modules/prettier/parser-meriyah.js +22 -1
- data/node_modules/prettier/parser-postcss.js +22 -1
- data/node_modules/prettier/parser-typescript.js +22 -1
- data/node_modules/prettier/parser-yaml.js +2 -2
- data/node_modules/prettier/third-party.js +1042 -833
- data/package.json +3 -3
- data/rubocop.yml +9 -0
- data/src/haml/parser.js +5 -4
- data/src/haml/printer.js +428 -18
- data/src/parser/parseSync.js +8 -6
- data/src/plugin.js +1 -1
- data/src/rbs/parser.js +1 -3
- data/src/rbs/printer.js +35 -7
- data/src/ruby/nodes/args.js +66 -22
- data/src/ruby/nodes/calls.js +8 -1
- data/src/ruby/nodes/conditionals.js +47 -45
- data/src/ruby/nodes/hashes.js +5 -14
- data/src/ruby/nodes/params.js +2 -9
- data/src/ruby/nodes/strings.js +95 -2
- data/src/ruby/parser.js +1 -3
- data/src/ruby/parser.rb +52 -29
- data/src/ruby/printer.js +10 -1
- data/src/utils/inlineEnsureParens.js +1 -0
- data/src/utils/skipAssignIndent.js +8 -1
- metadata +3 -12
- data/src/haml/nodes/comment.js +0 -27
- data/src/haml/nodes/doctype.js +0 -34
- data/src/haml/nodes/filter.js +0 -16
- data/src/haml/nodes/hamlComment.js +0 -21
- data/src/haml/nodes/plain.js +0 -6
- data/src/haml/nodes/root.js +0 -8
- data/src/haml/nodes/script.js +0 -33
- data/src/haml/nodes/silentScript.js +0 -59
- data/src/haml/nodes/tag.js +0 -232
data/src/parser/parseSync.js
CHANGED
@@ -135,15 +135,17 @@ function parseSync(parser, source, opts) {
|
|
135
135
|
// using unix sockets.
|
136
136
|
if (
|
137
137
|
stderr.includes("invalid option -- U") ||
|
138
|
+
stderr.includes("invalid option -- 'u'") ||
|
138
139
|
stderr.includes("Protocol not supported")
|
139
140
|
) {
|
140
141
|
throw new Error(`
|
141
|
-
@prettier/plugin-ruby uses
|
142
|
-
|
143
|
-
|
144
|
-
does not support unix sockets. To solve this either
|
145
|
-
of netcat that you're using and use a
|
146
|
-
the value of the rubyNetcatCommand
|
142
|
+
@prettier/plugin-ruby uses unix sockets to communicate between the node.js
|
143
|
+
process running prettier and an underlying Ruby process used for parsing.
|
144
|
+
Unfortunately the command that it tried to use to do that
|
145
|
+
(${netcat.command}) does not support unix sockets. To solve this either
|
146
|
+
uninstall the version of ${netcat.command} that you're using and use a
|
147
|
+
different implementation, or change the value of the rubyNetcatCommand
|
148
|
+
option in your prettier configuration.
|
147
149
|
`);
|
148
150
|
}
|
149
151
|
|
data/src/plugin.js
CHANGED
@@ -10,7 +10,7 @@ const hamlParser = require("./haml/parser");
|
|
10
10
|
/*
|
11
11
|
* metadata mostly pulled from linguist and rubocop:
|
12
12
|
* https://github.com/github/linguist/blob/master/lib/linguist/languages.yml
|
13
|
-
* https://github.com/rubocop
|
13
|
+
* https://github.com/rubocop/rubocop/blob/master/spec/rubocop/target_finder_spec.rb
|
14
14
|
*/
|
15
15
|
|
16
16
|
module.exports = {
|
data/src/rbs/parser.js
CHANGED
@@ -8,12 +8,10 @@ function parse(text, _parsers, opts) {
|
|
8
8
|
return parseSync("rbs", text, opts);
|
9
9
|
}
|
10
10
|
|
11
|
-
const pragmaPattern = /#\s*@(prettier|format)/;
|
12
|
-
|
13
11
|
// This function handles checking whether or not the source string has the
|
14
12
|
// pragma for prettier. This is an optional workflow for incremental adoption.
|
15
13
|
function hasPragma(text) {
|
16
|
-
return
|
14
|
+
return /^\s*#[^\S\n]*@(format|prettier)\s*(\n|$)/.test(text);
|
17
15
|
}
|
18
16
|
|
19
17
|
// This function is critical for comments and cursor support, and is responsible
|
data/src/rbs/printer.js
CHANGED
@@ -147,7 +147,7 @@ function printNode(path, opts, print) {
|
|
147
147
|
|
148
148
|
// This is the big function that prints out any individual type, which can
|
149
149
|
// look like all kinds of things, listed in the case statement below.
|
150
|
-
function printType(path, {
|
150
|
+
function printType(path, { forceParens = false } = {}) {
|
151
151
|
const node = path.getValue();
|
152
152
|
|
153
153
|
switch (node.class) {
|
@@ -157,7 +157,13 @@ function printNode(path, opts, print) {
|
|
157
157
|
}
|
158
158
|
return node.literal;
|
159
159
|
case "optional":
|
160
|
-
return concat([
|
160
|
+
return concat([
|
161
|
+
path.call(
|
162
|
+
(typePath) => printType(typePath, { forceParens: true }),
|
163
|
+
"type"
|
164
|
+
),
|
165
|
+
"?"
|
166
|
+
]);
|
161
167
|
case "tuple":
|
162
168
|
// If we don't have any sub types, we explicitly need the space in between
|
163
169
|
// the brackets to not confuse the parser.
|
@@ -173,14 +179,29 @@ function printNode(path, opts, print) {
|
|
173
179
|
join(concat([line, "| "]), path.map(printType, "types"))
|
174
180
|
);
|
175
181
|
|
176
|
-
if (
|
182
|
+
if (forceParens) {
|
183
|
+
return concat(["(", doc, ")"]);
|
184
|
+
}
|
185
|
+
|
186
|
+
return doc;
|
187
|
+
}
|
188
|
+
case "intersection": {
|
189
|
+
const doc = group(
|
190
|
+
join(
|
191
|
+
concat([line, "& "]),
|
192
|
+
path.map(
|
193
|
+
(typePath) => printType(typePath, { forceParens: true }),
|
194
|
+
"types"
|
195
|
+
)
|
196
|
+
)
|
197
|
+
);
|
198
|
+
|
199
|
+
if (forceParens) {
|
177
200
|
return concat(["(", doc, ")"]);
|
178
201
|
}
|
179
202
|
|
180
203
|
return doc;
|
181
204
|
}
|
182
|
-
case "intersection":
|
183
|
-
return group(join(concat([line, "& "]), path.map(printType, "types")));
|
184
205
|
case "class_singleton":
|
185
206
|
return concat(["singleton(", node.name, ")"]);
|
186
207
|
case "proc":
|
@@ -521,7 +542,7 @@ function printNode(path, opts, print) {
|
|
521
542
|
parts.push(
|
522
543
|
"-> ",
|
523
544
|
path.call(
|
524
|
-
(typePath) => printType(typePath, {
|
545
|
+
(typePath) => printType(typePath, { forceParens: true }),
|
525
546
|
"type",
|
526
547
|
"return_type"
|
527
548
|
)
|
@@ -609,7 +630,14 @@ function hasPrettierIgnore(path) {
|
|
609
630
|
return node.comment && node.comment.string.includes("prettier-ignore");
|
610
631
|
}
|
611
632
|
|
633
|
+
// This function handles adding the format pragma to a source string. This is an
|
634
|
+
// optional workflow for incremental adoption.
|
635
|
+
function insertPragma(text) {
|
636
|
+
return `# @format\n${text}`;
|
637
|
+
}
|
638
|
+
|
612
639
|
module.exports = {
|
613
640
|
print: printNode,
|
614
|
-
hasPrettierIgnore
|
641
|
+
hasPrettierIgnore,
|
642
|
+
insertPragma
|
615
643
|
};
|
data/src/ruby/nodes/args.js
CHANGED
@@ -108,12 +108,18 @@ function printArgs(path, { rubyToProc }, print) {
|
|
108
108
|
|
109
109
|
function printArgsAddBlock(path, opts, print) {
|
110
110
|
const node = path.getValue();
|
111
|
+
const blockNode = node.body[1];
|
112
|
+
|
111
113
|
const parts = path.call(print, "body", 0);
|
112
114
|
|
113
|
-
if (
|
115
|
+
if (blockNode) {
|
114
116
|
let blockDoc = path.call(print, "body", 1);
|
115
117
|
|
116
|
-
if (
|
118
|
+
if (!(blockNode.comments || []).some(({ leading }) => leading)) {
|
119
|
+
// If we don't have any leading comments, we can just prepend the
|
120
|
+
// operator.
|
121
|
+
blockDoc = concat(["&", blockDoc]);
|
122
|
+
} else if (Array.isArray(blockDoc[0])) {
|
117
123
|
// If we have a method call like:
|
118
124
|
//
|
119
125
|
// foo(
|
@@ -123,10 +129,20 @@ function printArgsAddBlock(path, opts, print) {
|
|
123
129
|
//
|
124
130
|
// then we need to make sure we don't accidentally prepend the operator
|
125
131
|
// before the comment.
|
126
|
-
|
132
|
+
//
|
133
|
+
// In prettier >= 2.3.0, the comments are printed as an array before the
|
134
|
+
// content. I don't love this kind of reflection, but it's the simplest
|
135
|
+
// way at the moment to get this right.
|
136
|
+
blockDoc = blockDoc[0].concat(
|
137
|
+
concat(["&", blockDoc[1]]),
|
138
|
+
blockDoc.slice(2)
|
139
|
+
);
|
127
140
|
} else {
|
128
|
-
//
|
129
|
-
|
141
|
+
// In prettier < 2.3.0, the comments are printed as part of a concat, so
|
142
|
+
// we can reflect on how many leading comments there are to determine
|
143
|
+
// which doc node we should modify.
|
144
|
+
const index = blockNode.comments.filter(({ leading }) => leading).length;
|
145
|
+
blockDoc.parts[index] = concat(["&", blockDoc.parts[index]]);
|
130
146
|
}
|
131
147
|
|
132
148
|
parts.push(blockDoc);
|
@@ -136,10 +152,34 @@ function printArgsAddBlock(path, opts, print) {
|
|
136
152
|
}
|
137
153
|
|
138
154
|
function printArgsAddStar(path, opts, print) {
|
139
|
-
|
140
|
-
|
155
|
+
let docs = [];
|
156
|
+
|
157
|
+
path.each((argPath, argIndex) => {
|
158
|
+
const doc = print(argPath);
|
159
|
+
|
160
|
+
// If it's the first child, then it's an array of args, so we're going to
|
161
|
+
// concat that onto the existing docs if there are any.
|
162
|
+
if (argIndex === 0) {
|
163
|
+
if (doc.length > 0) {
|
164
|
+
docs = docs.concat(doc);
|
165
|
+
}
|
166
|
+
return;
|
167
|
+
}
|
168
|
+
|
169
|
+
// If it's after the splat, then it's an individual arg, so we're just going
|
170
|
+
// to push it onto the array.
|
171
|
+
if (argIndex !== 1) {
|
172
|
+
docs.push(doc);
|
173
|
+
return;
|
174
|
+
}
|
175
|
+
|
176
|
+
// If we don't have any leading comments, we can just prepend the operator.
|
177
|
+
const argsNode = argPath.getValue();
|
178
|
+
if (!(argsNode.comments || []).some(({ leading }) => leading)) {
|
179
|
+
docs.push(concat(["*", doc]));
|
180
|
+
return;
|
181
|
+
}
|
141
182
|
|
142
|
-
if (node.body[1].comments) {
|
143
183
|
// If we have an array like:
|
144
184
|
//
|
145
185
|
// [
|
@@ -147,22 +187,26 @@ function printArgsAddStar(path, opts, print) {
|
|
147
187
|
// *values
|
148
188
|
// ]
|
149
189
|
//
|
150
|
-
// or if we have an array like:
|
151
|
-
//
|
152
|
-
// [
|
153
|
-
// *values # comment
|
154
|
-
// ]
|
155
|
-
//
|
156
190
|
// then we need to make sure we don't accidentally prepend the operator
|
157
|
-
// before the comment.
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
//
|
162
|
-
|
163
|
-
|
191
|
+
// before the comment(s).
|
192
|
+
//
|
193
|
+
// In prettier >= 2.3.0, the comments are printed as an array before the
|
194
|
+
// content. I don't love this kind of reflection, but it's the simplest way
|
195
|
+
// at the moment to get this right.
|
196
|
+
if (Array.isArray(doc[0])) {
|
197
|
+
docs.push(doc[0].concat(concat(["*", doc[1]]), doc.slice(2)));
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
|
201
|
+
// In prettier < 2.3.0, the comments are printed as part of a concat, so
|
202
|
+
// we can reflect on how many leading comments there are to determine which
|
203
|
+
// doc node we should modify.
|
204
|
+
const index = argsNode.comments.filter(({ leading }) => leading).length;
|
205
|
+
doc.parts[index] = concat(["*", doc.parts[index]]);
|
206
|
+
docs = docs.concat(doc);
|
207
|
+
}, "body");
|
164
208
|
|
165
|
-
return docs
|
209
|
+
return docs;
|
166
210
|
}
|
167
211
|
|
168
212
|
function printBlockArg(path, opts, print) {
|
data/src/ruby/nodes/calls.js
CHANGED
@@ -4,6 +4,7 @@ const {
|
|
4
4
|
hardline,
|
5
5
|
ifBreak,
|
6
6
|
indent,
|
7
|
+
join,
|
7
8
|
softline
|
8
9
|
} = require("../../prettier");
|
9
10
|
const { makeCall, noIndent } = require("../../utils");
|
@@ -133,7 +134,13 @@ function printMethodAddArg(path, opts, print) {
|
|
133
134
|
);
|
134
135
|
}
|
135
136
|
|
136
|
-
|
137
|
+
// If there are already parentheses, then we can just use the doc that's
|
138
|
+
// already printed.
|
139
|
+
if (argNode.type == "arg_paren") {
|
140
|
+
return concat([methodDoc, argsDoc]);
|
141
|
+
}
|
142
|
+
|
143
|
+
return concat([methodDoc, " ", join(", ", argsDoc), " "]);
|
137
144
|
}
|
138
145
|
|
139
146
|
function printMethodAddBlock(path, opts, print) {
|
@@ -190,57 +190,59 @@ const canTernary = (path) => {
|
|
190
190
|
};
|
191
191
|
|
192
192
|
// A normalized print function for both `if` and `unless` nodes.
|
193
|
-
const printConditional =
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
193
|
+
const printConditional =
|
194
|
+
(keyword) =>
|
195
|
+
(path, { rubyModifier }, print) => {
|
196
|
+
if (canTernary(path)) {
|
197
|
+
let ternaryParts = [path.call(print, "body", 0), " ? "].concat(
|
198
|
+
printTernaryClauses(
|
199
|
+
keyword,
|
200
|
+
path.call(print, "body", 1),
|
201
|
+
path.call(print, "body", 2, "body", 0)
|
202
|
+
)
|
203
|
+
);
|
204
|
+
|
205
|
+
if (["binary", "call"].includes(path.getParentNode().type)) {
|
206
|
+
ternaryParts = ["("].concat(ternaryParts).concat(")");
|
207
|
+
}
|
208
|
+
|
209
|
+
return group(
|
210
|
+
ifBreak(printWithAddition(keyword, path, print), concat(ternaryParts))
|
211
|
+
);
|
205
212
|
}
|
206
213
|
|
207
|
-
|
208
|
-
ifBreak(printWithAddition(keyword, path, print), concat(ternaryParts))
|
209
|
-
);
|
210
|
-
}
|
211
|
-
|
212
|
-
const [predicate, statements, addition] = path.getValue().body;
|
214
|
+
const [predicate, statements, addition] = path.getValue().body;
|
213
215
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
216
|
+
// If there's an additional clause that wasn't matched earlier, we know we
|
217
|
+
// can't go for the inline option.
|
218
|
+
if (addition) {
|
219
|
+
return group(printWithAddition(keyword, path, print, { breaking: true }));
|
220
|
+
}
|
219
221
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
222
|
+
// If the body of the conditional is empty, then we explicitly have to use the
|
223
|
+
// block form.
|
224
|
+
if (isEmptyStmts(statements)) {
|
225
|
+
return concat([
|
226
|
+
`${keyword} `,
|
227
|
+
align(keyword.length + 1, path.call(print, "body", 0)),
|
228
|
+
concat([hardline, "end"])
|
229
|
+
]);
|
230
|
+
}
|
229
231
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
232
|
+
// If the predicate of the conditional contains an assignment, then we can't
|
233
|
+
// know for sure that it doesn't impact the body of the conditional, so we
|
234
|
+
// have to default to the block form.
|
235
|
+
if (containsAssignment(predicate)) {
|
236
|
+
return concat([
|
237
|
+
`${keyword} `,
|
238
|
+
align(keyword.length + 1, path.call(print, "body", 0)),
|
239
|
+
indent(concat([hardline, path.call(print, "body", 1)])),
|
240
|
+
concat([hardline, "end"])
|
241
|
+
]);
|
242
|
+
}
|
241
243
|
|
242
|
-
|
243
|
-
};
|
244
|
+
return printSingle(keyword)(path, { rubyModifier }, print);
|
245
|
+
};
|
244
246
|
|
245
247
|
module.exports = {
|
246
248
|
else: (path, opts, print) => {
|
data/src/ruby/nodes/hashes.js
CHANGED
@@ -56,28 +56,19 @@ function printHashKeyLabel(path, print) {
|
|
56
56
|
case "symbol_literal":
|
57
57
|
return concat([path.call(print, "body", 0), ":"]);
|
58
58
|
case "dyna_symbol": {
|
59
|
-
|
60
|
-
|
61
|
-
// We're going to slice off the starting colon character so that we can
|
62
|
-
// move it to the end. If there are comments, then we're going to go
|
63
|
-
// further into the printed doc nodes.
|
64
|
-
if (parts[0] === ":") {
|
65
|
-
parts.splice(0, 1);
|
66
|
-
} else {
|
67
|
-
parts[1].parts.splice(0, 1);
|
68
|
-
}
|
69
|
-
|
70
|
-
return concat(parts.concat(":"));
|
59
|
+
return concat([print(path), ":"]);
|
71
60
|
}
|
72
61
|
}
|
73
62
|
}
|
74
63
|
|
75
64
|
function printHashKeyRocket(path, print) {
|
76
65
|
const node = path.getValue();
|
77
|
-
|
66
|
+
let doc = print(path);
|
78
67
|
|
79
68
|
if (node.type === "@label") {
|
80
|
-
|
69
|
+
doc = concat([":", doc.slice(0, doc.length - 1)]);
|
70
|
+
} else if (node.type === "dyna_symbol") {
|
71
|
+
doc = concat([":", doc]);
|
81
72
|
}
|
82
73
|
|
83
74
|
return concat([doc, " =>"]);
|
data/src/ruby/nodes/params.js
CHANGED
@@ -17,15 +17,8 @@ function printRestParam(symbol) {
|
|
17
17
|
}
|
18
18
|
|
19
19
|
function printParams(path, opts, print) {
|
20
|
-
const [
|
21
|
-
|
22
|
-
optls,
|
23
|
-
rest,
|
24
|
-
post,
|
25
|
-
kwargs,
|
26
|
-
kwargRest,
|
27
|
-
block
|
28
|
-
] = path.getValue().body;
|
20
|
+
const [reqs, optls, rest, post, kwargs, kwargRest, block] =
|
21
|
+
path.getValue().body;
|
29
22
|
let parts = [];
|
30
23
|
|
31
24
|
if (reqs) {
|
data/src/ruby/nodes/strings.js
CHANGED
@@ -82,13 +82,106 @@ function printChar(path, { rubySingleQuote }, _print) {
|
|
82
82
|
return concat([quote, body.slice(1), quote]);
|
83
83
|
}
|
84
84
|
|
85
|
+
function printPercentSDynaSymbol(path, opts, print) {
|
86
|
+
const node = path.getValue();
|
87
|
+
const parts = [];
|
88
|
+
|
89
|
+
// Push on the quote, which includes the opening character.
|
90
|
+
parts.push(node.quote);
|
91
|
+
|
92
|
+
path.each((childPath) => {
|
93
|
+
const childNode = childPath.getValue();
|
94
|
+
|
95
|
+
if (childNode.type !== "@tstring_content") {
|
96
|
+
// Here we are printing an embedded variable or expression.
|
97
|
+
parts.push(print(childPath));
|
98
|
+
} else {
|
99
|
+
// Here we are printing plain string content.
|
100
|
+
parts.push(join(literalline, childNode.body.split("\n")));
|
101
|
+
}
|
102
|
+
}, "body");
|
103
|
+
|
104
|
+
// Push on the closing character, which is the opposite of the third
|
105
|
+
// character from the opening.
|
106
|
+
parts.push(quotePairs[node.quote[2]]);
|
107
|
+
|
108
|
+
return concat(parts);
|
109
|
+
}
|
110
|
+
|
111
|
+
// We don't actually want to print %s symbols, as they're much more rarely seen
|
112
|
+
// in the wild. But we're going to be forced into it if it's a multi-line symbol
|
113
|
+
// or if the quoting would get super complicated.
|
114
|
+
function shouldPrintPercentSDynaSymbol(node) {
|
115
|
+
// We shouldn't print a %s dyna symbol if it was not already that way in the
|
116
|
+
// original source.
|
117
|
+
if (node.quote[0] !== "%") {
|
118
|
+
return false;
|
119
|
+
}
|
120
|
+
|
121
|
+
// Here we're going to check if there is a closing character, a new line, or a
|
122
|
+
// quote in the content of the dyna symbol. If there is, then quoting could
|
123
|
+
// get weird, so just bail out and stick to the original bounds in the source.
|
124
|
+
const closing = quotePairs[node.quote[2]];
|
125
|
+
|
126
|
+
return node.body.some(
|
127
|
+
(child) =>
|
128
|
+
child.type === "@tstring_content" &&
|
129
|
+
(child.body.includes("\n") ||
|
130
|
+
child.body.includes(closing) ||
|
131
|
+
child.body.includes("'") ||
|
132
|
+
child.body.includes('"'))
|
133
|
+
);
|
134
|
+
}
|
135
|
+
|
85
136
|
// Prints a dynamic symbol. Assumes there's a quote property attached to the
|
86
137
|
// node that will tell us which quote to use when printing. We're just going to
|
87
138
|
// use whatever quote was provided.
|
139
|
+
//
|
140
|
+
// In the case of a plain dyna symbol, node.quote will be either :" or :'
|
141
|
+
// For %s dyna symbols, node.quote will be %s[, %s(, %s{, or %s<
|
88
142
|
function printDynaSymbol(path, opts, print) {
|
89
|
-
const
|
143
|
+
const node = path.getValue();
|
144
|
+
|
145
|
+
if (shouldPrintPercentSDynaSymbol(node)) {
|
146
|
+
return printPercentSDynaSymbol(path, opts, print);
|
147
|
+
}
|
148
|
+
|
149
|
+
const parts = [];
|
150
|
+
let quote;
|
151
|
+
|
152
|
+
if (isQuoteLocked(node)) {
|
153
|
+
if (node.quote.startsWith("%")) {
|
154
|
+
quote = opts.rubySingleQuote ? "'" : '"';
|
155
|
+
} else {
|
156
|
+
quote = node.quote.slice(1);
|
157
|
+
}
|
158
|
+
} else {
|
159
|
+
quote = opts.rubySingleQuote && isSingleQuotable(node) ? "'" : '"';
|
160
|
+
}
|
161
|
+
|
162
|
+
parts.push(quote);
|
163
|
+
path.each((childPath) => {
|
164
|
+
const child = childPath.getValue();
|
165
|
+
|
166
|
+
if (child.type !== "@tstring_content") {
|
167
|
+
parts.push(print(childPath));
|
168
|
+
} else {
|
169
|
+
parts.push(
|
170
|
+
join(literalline, normalizeQuotes(child.body, quote).split("\n"))
|
171
|
+
);
|
172
|
+
}
|
173
|
+
}, "body");
|
174
|
+
|
175
|
+
parts.push(quote);
|
176
|
+
|
177
|
+
// If we're inside of an assoc_new node as the key, then it will handle
|
178
|
+
// printing the : on its own since it could change sides.
|
179
|
+
const parentNode = path.getParentNode();
|
180
|
+
if (parentNode.type !== "assoc_new" || parentNode.body[0] !== node) {
|
181
|
+
parts.unshift(":");
|
182
|
+
}
|
90
183
|
|
91
|
-
return concat(
|
184
|
+
return concat(parts);
|
92
185
|
}
|
93
186
|
|
94
187
|
function printStringConcat(path, opts, print) {
|