prettier 0.17.0 → 0.19.1
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 +410 -201
- data/CONTRIBUTING.md +1 -1
- data/LICENSE +1 -1
- data/README.md +33 -12
- data/node_modules/prettier/bin-prettier.js +33712 -25689
- data/node_modules/prettier/index.js +32389 -24963
- data/node_modules/prettier/third-party.js +10733 -3849
- data/package.json +35 -7
- data/src/haml.js +3 -3
- data/src/haml/embed.js +2 -2
- data/src/haml/nodes/silentScript.js +32 -3
- data/src/haml/nodes/tag.js +14 -8
- data/src/haml/parse.rb +6 -7
- data/src/nodes/alias.js +2 -2
- data/src/nodes/args.js +9 -2
- data/src/nodes/arrays.js +11 -7
- data/src/nodes/blocks.js +7 -8
- data/src/nodes/calls.js +45 -10
- data/src/nodes/case.js +1 -1
- data/src/nodes/commands.js +3 -3
- data/src/nodes/conditionals.js +19 -15
- data/src/nodes/hashes.js +2 -2
- data/src/nodes/hooks.js +1 -1
- data/src/nodes/ints.js +1 -1
- data/src/nodes/lambdas.js +1 -1
- data/src/nodes/loops.js +16 -0
- data/src/nodes/methods.js +2 -2
- data/src/nodes/operators.js +11 -3
- data/src/nodes/params.js +4 -2
- data/src/nodes/regexp.js +1 -1
- data/src/nodes/rescue.js +5 -1
- data/src/nodes/return.js +11 -1
- data/src/nodes/strings.js +54 -77
- data/src/parse.js +24 -4
- data/src/prettier.js +0 -1
- data/src/ripper.rb +29 -20
- data/src/ruby.js +13 -4
- data/src/toProc.js +30 -3
- data/src/utils.js +6 -6
- metadata +12 -13
- data/src/escapePattern.js +0 -45
data/src/nodes/case.js
CHANGED
@@ -42,7 +42,7 @@ module.exports = {
|
|
42
42
|
|
43
43
|
// It's possible in a when to just have empty void statements, in which case
|
44
44
|
// we would skip adding the body.
|
45
|
-
if (!stmts.parts.every(part => !part)) {
|
45
|
+
if (!stmts.parts.every((part) => !part)) {
|
46
46
|
parts.push(indent(concat([hardline, stmts])));
|
47
47
|
}
|
48
48
|
|
data/src/nodes/commands.js
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
const { align, concat, group, ifBreak, join, line } = require("../prettier");
|
2
2
|
const { docLength, makeArgs, makeCall } = require("../utils");
|
3
3
|
|
4
|
-
const hasDef = node =>
|
4
|
+
const hasDef = (node) =>
|
5
5
|
node.body[1].type === "args_add_block" &&
|
6
6
|
node.body[1].body[0].type === "args" &&
|
7
7
|
node.body[1].body[0].body[0] &&
|
8
|
-
node.body[1].body[0].body[0].type
|
8
|
+
["def", "defs"].includes(node.body[1].body[0].body[0].type);
|
9
9
|
|
10
10
|
// Very special handling case for rspec matchers. In general with rspec matchers
|
11
11
|
// you expect to see something like:
|
@@ -20,7 +20,7 @@ const hasDef = node =>
|
|
20
20
|
//
|
21
21
|
// In this case the arguments are aligned to the left side as opposed to being
|
22
22
|
// aligned with the `receive` call.
|
23
|
-
const skipArgsAlign = path =>
|
23
|
+
const skipArgsAlign = (path) =>
|
24
24
|
["to", "not_to"].includes(path.getValue().body[2].body);
|
25
25
|
|
26
26
|
module.exports = {
|
data/src/nodes/conditionals.js
CHANGED
@@ -23,7 +23,7 @@ const printWithAddition = (keyword, path, print, { breaking = false } = {}) =>
|
|
23
23
|
// For the unary `not` operator, we need to explicitly add parentheses to it in
|
24
24
|
// order for it to be valid from within a ternary. Otherwise if the clause of
|
25
25
|
// the ternary isn't a unary `not`, we can just pass it along.
|
26
|
-
const printTernaryClause = clause => {
|
26
|
+
const printTernaryClause = (clause) => {
|
27
27
|
if (clause.type === "concat") {
|
28
28
|
const [part] = clause.parts;
|
29
29
|
|
@@ -75,23 +75,21 @@ const printTernary = (path, _opts, print) => {
|
|
75
75
|
);
|
76
76
|
};
|
77
77
|
|
78
|
-
|
79
|
-
|
78
|
+
// Prints an `if_mod` or `unless_mod` node. Because it was previously in the
|
79
|
+
// modifier form, we're guaranteed to not have an additional node, so we can
|
80
|
+
// just work with the predicate and the body.
|
81
|
+
const printSingle = (keyword) => (path, { inlineConditionals }, print) => {
|
82
|
+
const multiline = concat([
|
80
83
|
`${keyword} `,
|
81
84
|
align(keyword.length + 1, path.call(print, "body", 0)),
|
82
85
|
indent(concat([softline, path.call(print, "body", 1)])),
|
83
86
|
concat([softline, "end"])
|
84
87
|
]);
|
85
88
|
|
86
|
-
// Prints an `if_mod` or `unless_mod` node. Because it was previously in the
|
87
|
-
// modifier form, we're guaranteed to not have an additional node, so we can
|
88
|
-
// just work with the predicate and the body.
|
89
|
-
const printSingle = keyword => (path, { inlineConditionals }, print) => {
|
90
|
-
const multiline = makeSingleBlockForm(keyword, path, print);
|
91
|
-
|
92
89
|
const [_predicate, stmts] = path.getValue().body;
|
93
90
|
const hasComments =
|
94
|
-
stmts.type === "stmts" &&
|
91
|
+
stmts.type === "stmts" &&
|
92
|
+
stmts.body.some((stmt) => stmt.type === "@comment");
|
95
93
|
|
96
94
|
if (!inlineConditionals || hasComments) {
|
97
95
|
return multiline;
|
@@ -155,7 +153,7 @@ const noTernary = [
|
|
155
153
|
// Certain expressions cannot be reduced to a ternary without adding parens
|
156
154
|
// around them. In this case we say they cannot be ternaried and default instead
|
157
155
|
// to breaking them into multiple lines.
|
158
|
-
const canTernaryStmts = stmts => {
|
156
|
+
const canTernaryStmts = (stmts) => {
|
159
157
|
if (stmts.body.length !== 1) {
|
160
158
|
return false;
|
161
159
|
}
|
@@ -178,10 +176,11 @@ const canTernaryStmts = stmts => {
|
|
178
176
|
// is of the "else" type. Both the body of the main node and the body of the
|
179
177
|
// additional node must have only one statement, and that statement list must
|
180
178
|
// pass the `canTernaryStmts` check.
|
181
|
-
const canTernary = path => {
|
182
|
-
const [
|
179
|
+
const canTernary = (path) => {
|
180
|
+
const [predicate, stmts, addition] = path.getValue().body;
|
183
181
|
|
184
182
|
return (
|
183
|
+
!["assign", "opassign"].includes(predicate.type) &&
|
185
184
|
addition &&
|
186
185
|
addition.type === "else" &&
|
187
186
|
[stmts, addition.body[0]].every(canTernaryStmts)
|
@@ -189,7 +188,7 @@ const canTernary = path => {
|
|
189
188
|
};
|
190
189
|
|
191
190
|
// A normalized print function for both `if` and `unless` nodes.
|
192
|
-
const printConditional = keyword => (path, { inlineConditionals }, print) => {
|
191
|
+
const printConditional = (keyword) => (path, { inlineConditionals }, print) => {
|
193
192
|
if (canTernary(path)) {
|
194
193
|
let ternaryParts = [path.call(print, "body", 0), " ? "].concat(
|
195
194
|
printTernaryClauses(
|
@@ -230,7 +229,12 @@ const printConditional = keyword => (path, { inlineConditionals }, print) => {
|
|
230
229
|
// know for sure that it doesn't impact the body of the conditional, so we
|
231
230
|
// have to default to the block form.
|
232
231
|
if (containsAssignment(predicate)) {
|
233
|
-
return
|
232
|
+
return concat([
|
233
|
+
`${keyword} `,
|
234
|
+
align(keyword.length + 1, path.call(print, "body", 0)),
|
235
|
+
indent(concat([hardline, path.call(print, "body", 1)])),
|
236
|
+
concat([hardline, "end"])
|
237
|
+
]);
|
234
238
|
}
|
235
239
|
|
236
240
|
return printSingle(keyword)(path, { inlineConditionals }, print);
|
data/src/nodes/hashes.js
CHANGED
@@ -12,7 +12,7 @@ const { prefix, skipAssignIndent } = require("../utils");
|
|
12
12
|
const nodeDive = (node, steps) => {
|
13
13
|
let current = node;
|
14
14
|
|
15
|
-
steps.forEach(step => {
|
15
|
+
steps.forEach((step) => {
|
16
16
|
current = current[step];
|
17
17
|
});
|
18
18
|
|
@@ -29,7 +29,7 @@ const nodeDive = (node, steps) => {
|
|
29
29
|
//
|
30
30
|
// This function represents that check, as it determines if it can convert the
|
31
31
|
// symbol node into a hash label.
|
32
|
-
const isValidHashLabel = symbolLiteral => {
|
32
|
+
const isValidHashLabel = (symbolLiteral) => {
|
33
33
|
const label = symbolLiteral.body[0].body[0].body;
|
34
34
|
return label.match(/^[_A-Za-z]/) && !label.endsWith("=");
|
35
35
|
};
|
data/src/nodes/hooks.js
CHANGED
data/src/nodes/ints.js
CHANGED
@@ -11,7 +11,7 @@ module.exports = {
|
|
11
11
|
// If the number is a base 10 number, is sufficiently large, and is not
|
12
12
|
// already formatted with underscores, then add them in in between the
|
13
13
|
// numbers every three characters starting from the right.
|
14
|
-
if (!body.startsWith("0") && body.length >=
|
14
|
+
if (!body.startsWith("0") && body.length >= 5 && !body.includes("_")) {
|
15
15
|
return ` ${body}`
|
16
16
|
.slice((body.length + 2) % 3)
|
17
17
|
.match(/.{3}/g)
|
data/src/nodes/lambdas.js
CHANGED
@@ -21,7 +21,7 @@ module.exports = {
|
|
21
21
|
paramsConcat = path.call(print, "body", 0, "body", 0);
|
22
22
|
}
|
23
23
|
|
24
|
-
const noParams = params.body.every(type => !type);
|
24
|
+
const noParams = params.body.every((type) => !type);
|
25
25
|
const inlineLambda = concat([
|
26
26
|
"->",
|
27
27
|
noParams ? "" : concat(["(", paramsConcat, ")"]),
|
data/src/nodes/loops.js
CHANGED
@@ -10,6 +10,22 @@ const {
|
|
10
10
|
const { containsAssignment } = require("../utils");
|
11
11
|
|
12
12
|
const printLoop = (keyword, modifier) => (path, { inlineLoops }, print) => {
|
13
|
+
const [_predicate, statements] = path.getValue().body;
|
14
|
+
|
15
|
+
// If the only statement inside this while loop is a void statement, then we
|
16
|
+
// can shorten to just displaying the predicate and then a semicolon.
|
17
|
+
if (statements.body.length === 1 && statements.body[0].type === "void_stmt") {
|
18
|
+
return group(
|
19
|
+
concat([
|
20
|
+
keyword,
|
21
|
+
" ",
|
22
|
+
path.call(print, "body", 0),
|
23
|
+
ifBreak(softline, "; "),
|
24
|
+
"end"
|
25
|
+
])
|
26
|
+
);
|
27
|
+
}
|
28
|
+
|
13
29
|
let inlineParts = [
|
14
30
|
path.call(print, "body", 1),
|
15
31
|
` ${keyword} `,
|
data/src/nodes/methods.js
CHANGED
@@ -9,7 +9,7 @@ const {
|
|
9
9
|
} = require("../prettier");
|
10
10
|
const { first, literal } = require("../utils");
|
11
11
|
|
12
|
-
const printMethod = offset => (path, opts, print) => {
|
12
|
+
const printMethod = (offset) => (path, opts, print) => {
|
13
13
|
const [_name, params, body] = path.getValue().body.slice(offset);
|
14
14
|
const declaration = ["def "];
|
15
15
|
|
@@ -21,7 +21,7 @@ const printMethod = offset => (path, opts, print) => {
|
|
21
21
|
|
22
22
|
// In case there are no parens but there are arguments
|
23
23
|
const parens =
|
24
|
-
params.type === "params" && params.body.some(paramType => paramType);
|
24
|
+
params.type === "params" && params.body.some((paramType) => paramType);
|
25
25
|
|
26
26
|
declaration.push(
|
27
27
|
path.call(print, "body", offset),
|
data/src/nodes/operators.js
CHANGED
@@ -7,10 +7,18 @@ module.exports = {
|
|
7
7
|
|
8
8
|
return group(
|
9
9
|
concat([
|
10
|
-
|
11
|
-
operator,
|
10
|
+
group(path.call(print, "body", 0)),
|
12
11
|
indent(
|
13
|
-
concat([
|
12
|
+
concat([
|
13
|
+
useNoSpace ? "" : " ",
|
14
|
+
group(
|
15
|
+
concat([
|
16
|
+
operator,
|
17
|
+
useNoSpace ? softline : line,
|
18
|
+
path.call(print, "body", 2)
|
19
|
+
])
|
20
|
+
)
|
21
|
+
])
|
14
22
|
)
|
15
23
|
])
|
16
24
|
);
|
data/src/nodes/params.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
const { concat, group, join, line } = require("../prettier");
|
2
|
+
const { literal } = require("../utils");
|
2
3
|
|
3
|
-
const printGenericRestParam = symbol => (path, opts, print) =>
|
4
|
+
const printGenericRestParam = (symbol) => (path, opts, print) =>
|
4
5
|
path.getValue().body[0]
|
5
6
|
? concat([symbol, path.call(print, "body", 0)])
|
6
7
|
: symbol;
|
@@ -53,7 +54,7 @@ const printParams = (path, opts, print) => {
|
|
53
54
|
}
|
54
55
|
|
55
56
|
if (kwargRest) {
|
56
|
-
parts.push(path.call(print, "body", 5));
|
57
|
+
parts.push(kwargRest === "nil" ? "**nil" : path.call(print, "body", 5));
|
57
58
|
}
|
58
59
|
|
59
60
|
if (block) {
|
@@ -79,6 +80,7 @@ const paramError = () => {
|
|
79
80
|
};
|
80
81
|
|
81
82
|
module.exports = {
|
83
|
+
args_forward: literal("..."),
|
82
84
|
kwrest_param: printGenericRestParam("**"),
|
83
85
|
rest_param: printGenericRestParam("*"),
|
84
86
|
params: printParams,
|
data/src/nodes/regexp.js
CHANGED
@@ -7,7 +7,7 @@ module.exports = {
|
|
7
7
|
const [contents, ending] = path.map(print, "body");
|
8
8
|
|
9
9
|
const useBraces = contents.some(
|
10
|
-
content => typeof content === "string" && content.includes("/")
|
10
|
+
(content) => typeof content === "string" && content.includes("/")
|
11
11
|
);
|
12
12
|
const parts = [useBraces ? "%r{" : "/"]
|
13
13
|
.concat(contents)
|
data/src/nodes/rescue.js
CHANGED
@@ -53,7 +53,11 @@ module.exports = {
|
|
53
53
|
parts.push(" StandardError");
|
54
54
|
}
|
55
55
|
|
56
|
-
|
56
|
+
const rescueBody = path.call(print, "body", 2);
|
57
|
+
|
58
|
+
if (rescueBody.parts.length > 0) {
|
59
|
+
parts.push(indent(concat([hardline, rescueBody])));
|
60
|
+
}
|
57
61
|
|
58
62
|
// This is the next clause on the `begin` statement, either another
|
59
63
|
// `rescue`, and `ensure`, or an `else` clause.
|
data/src/nodes/return.js
CHANGED
@@ -9,6 +9,16 @@ const {
|
|
9
9
|
} = require("../prettier");
|
10
10
|
const { literal } = require("../utils");
|
11
11
|
|
12
|
+
// You can't skip the parentheses if you have the `and` or `or` operator,
|
13
|
+
// because they have low enough operator precedence that you need to explicitly
|
14
|
+
// keep them in there.
|
15
|
+
const canSkipParens = (args) => {
|
16
|
+
const statement = args.body[0].body[0].body[0];
|
17
|
+
return (
|
18
|
+
statement.type !== "binary" || !["and", "or"].includes(statement.body[1])
|
19
|
+
);
|
20
|
+
};
|
21
|
+
|
12
22
|
const printReturn = (path, opts, print) => {
|
13
23
|
let args = path.getValue().body[0].body[0];
|
14
24
|
let steps = ["body", 0, "body", 0];
|
@@ -20,7 +30,7 @@ const printReturn = (path, opts, print) => {
|
|
20
30
|
// If the body of the return contains parens, then just skip directly to the
|
21
31
|
// content of the parens so that we can skip printing parens if we don't
|
22
32
|
// want them.
|
23
|
-
if (args.body[0] && args.body[0].type === "paren") {
|
33
|
+
if (args.body[0] && args.body[0].type === "paren" && canSkipParens(args)) {
|
24
34
|
args = args.body[0].body[0];
|
25
35
|
steps = steps.concat("body", 0, "body", 0);
|
26
36
|
}
|
data/src/nodes/strings.js
CHANGED
@@ -7,39 +7,31 @@ const {
|
|
7
7
|
softline,
|
8
8
|
join
|
9
9
|
} = require("../prettier");
|
10
|
+
|
10
11
|
const { concatBody, empty, makeList, prefix, surround } = require("../utils");
|
11
|
-
const escapePattern = require("../escapePattern");
|
12
12
|
|
13
13
|
// If there is some part of this string that matches an escape sequence or that
|
14
14
|
// contains the interpolation pattern ("#{"), then we are locked into whichever
|
15
15
|
// quote the user chose. (If they chose single quotes, then double quoting
|
16
16
|
// would activate the escape sequence, and if they chose double quotes, then
|
17
17
|
// single quotes would deactivate it.)
|
18
|
-
const isQuoteLocked = string =>
|
18
|
+
const isQuoteLocked = (string) =>
|
19
19
|
string.body.some(
|
20
|
-
part =>
|
20
|
+
(part) =>
|
21
21
|
part.type === "@tstring_content" &&
|
22
|
-
(
|
22
|
+
(part.body.includes("#{") || part.body.includes("\\"))
|
23
23
|
);
|
24
24
|
|
25
25
|
// A string is considered to be able to use single quotes if it contains only
|
26
26
|
// plain string content and that content does not contain a single quote.
|
27
|
-
const isSingleQuotable = string =>
|
27
|
+
const isSingleQuotable = (string) =>
|
28
28
|
string.body.every(
|
29
|
-
part => part.type === "@tstring_content" && !part.body.includes("'")
|
29
|
+
(part) => part.type === "@tstring_content" && !part.body.includes("'")
|
30
30
|
);
|
31
31
|
|
32
|
-
const getStringQuote = (string, preferSingleQuotes) => {
|
33
|
-
if (isQuoteLocked(string)) {
|
34
|
-
return string.quote;
|
35
|
-
}
|
36
|
-
|
37
|
-
return preferSingleQuotes && isSingleQuotable(string) ? "'" : '"';
|
38
|
-
};
|
39
|
-
|
40
32
|
const quotePattern = new RegExp("\\\\([\\s\\S])|(['\"])", "g");
|
41
33
|
|
42
|
-
const
|
34
|
+
const normalizeQuotes = (content, enclosingQuote, originalQuote) => {
|
43
35
|
const replaceOther = ["'", '"'].includes(originalQuote);
|
44
36
|
const otherQuote = enclosingQuote === '"' ? "'" : '"';
|
45
37
|
|
@@ -62,51 +54,24 @@ const makeString = (content, enclosingQuote, originalQuote) => {
|
|
62
54
|
});
|
63
55
|
};
|
64
56
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
const makeHeredocLines = parts => {
|
72
|
-
let lines = [];
|
73
|
-
let currentLine = [];
|
74
|
-
|
75
|
-
parts.forEach(part => {
|
76
|
-
if (part.type === "group" || !part.includes("\n")) {
|
77
|
-
// In this case we've either hit an embedded expression or the piece of
|
78
|
-
// the current line that we're looking at is in the middle of two of them,
|
79
|
-
// so we just push onto the current line and continue on.
|
80
|
-
currentLine.push(part);
|
81
|
-
return;
|
82
|
-
}
|
83
|
-
|
84
|
-
let splits = part.split("\n");
|
85
|
-
if (splits[splits.length - 1] === "") {
|
86
|
-
// If a line ends with a newline, then we end up with an empty string at
|
87
|
-
// the end of the splits, we just pop it off here since we'll handle the
|
88
|
-
// newlines later.
|
89
|
-
splits = splits.slice(0, -1);
|
90
|
-
}
|
91
|
-
|
92
|
-
if (currentLine.length > 0) {
|
93
|
-
lines.push(concat(currentLine.concat(splits[0])));
|
94
|
-
currentLine = [];
|
95
|
-
} else {
|
96
|
-
lines.push(splits[0]);
|
97
|
-
}
|
57
|
+
const quotePairs = {
|
58
|
+
"(": ")",
|
59
|
+
"[": "]",
|
60
|
+
"{": "}",
|
61
|
+
"<": ">"
|
62
|
+
};
|
98
63
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
});
|
64
|
+
const getClosingQuote = (quote) => {
|
65
|
+
if (!quote.startsWith("%")) {
|
66
|
+
return quote;
|
67
|
+
}
|
104
68
|
|
105
|
-
|
106
|
-
|
69
|
+
const boundary = /%q?(.)/.exec(quote)[1];
|
70
|
+
if (boundary in quotePairs) {
|
71
|
+
return quotePairs[boundary];
|
107
72
|
}
|
108
73
|
|
109
|
-
return
|
74
|
+
return boundary;
|
110
75
|
};
|
111
76
|
|
112
77
|
module.exports = {
|
@@ -121,21 +86,24 @@ module.exports = {
|
|
121
86
|
return body.length === 2 ? concat([quote, body.slice(1), quote]) : body;
|
122
87
|
},
|
123
88
|
dyna_symbol: (path, opts, print) => {
|
124
|
-
const { quote } = path.getValue()
|
89
|
+
const { quote } = path.getValue();
|
125
90
|
|
126
91
|
return concat([":", quote, concat(path.call(print, "body", 0)), quote]);
|
127
92
|
},
|
128
93
|
heredoc: (path, opts, print) => {
|
129
|
-
const { beging, ending } = path.getValue();
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
94
|
+
const { beging, body, ending } = path.getValue();
|
95
|
+
|
96
|
+
const parts = body.map((part, index) => {
|
97
|
+
if (part.type !== "@tstring_content") {
|
98
|
+
// In this case, the part of the string is an embedded expression
|
99
|
+
return path.call(print, "body", index);
|
100
|
+
}
|
101
|
+
|
102
|
+
// In this case, the part of the string is just regular string content
|
103
|
+
return join(literalline, part.body.split("\n"));
|
104
|
+
});
|
105
|
+
|
106
|
+
return concat([beging, literalline, concat(parts), ending]);
|
139
107
|
},
|
140
108
|
string: makeList,
|
141
109
|
string_concat: (path, opts, print) =>
|
@@ -162,7 +130,8 @@ module.exports = {
|
|
162
130
|
);
|
163
131
|
},
|
164
132
|
string_literal: (path, { preferSingleQuotes }, print) => {
|
165
|
-
const
|
133
|
+
const stringLiteral = path.getValue();
|
134
|
+
const string = stringLiteral.body[0];
|
166
135
|
|
167
136
|
// If this string is actually a heredoc, bail out and return to the print
|
168
137
|
// function for heredocs
|
@@ -176,20 +145,28 @@ module.exports = {
|
|
176
145
|
return preferSingleQuotes ? "''" : '""';
|
177
146
|
}
|
178
147
|
|
179
|
-
|
180
|
-
|
148
|
+
// Determine the quote that should enclose the new string
|
149
|
+
let quote;
|
150
|
+
if (isQuoteLocked(string)) {
|
151
|
+
({ quote } = stringLiteral);
|
152
|
+
} else {
|
153
|
+
quote = preferSingleQuotes && isSingleQuotable(string) ? "'" : '"';
|
154
|
+
}
|
181
155
|
|
182
|
-
string.body.
|
183
|
-
if (part.type
|
184
|
-
// In this case, the part of the string is just regular string content
|
185
|
-
parts.push(makeString(part.body, quote, string.quote));
|
186
|
-
} else {
|
156
|
+
const parts = string.body.map((part, index) => {
|
157
|
+
if (part.type !== "@tstring_content") {
|
187
158
|
// In this case, the part of the string is an embedded expression
|
188
|
-
|
159
|
+
return path.call(print, "body", 0, "body", index);
|
189
160
|
}
|
161
|
+
|
162
|
+
// In this case, the part of the string is just regular string content
|
163
|
+
return join(
|
164
|
+
literalline,
|
165
|
+
normalizeQuotes(part.body, quote, stringLiteral.quote).split("\n")
|
166
|
+
);
|
190
167
|
});
|
191
168
|
|
192
|
-
return concat([quote].concat(parts).concat(
|
169
|
+
return concat([quote].concat(parts).concat(getClosingQuote(quote)));
|
193
170
|
},
|
194
171
|
symbol: prefix(":"),
|
195
172
|
symbol_literal: concatBody,
|