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/regexp.js
CHANGED
@@ -1,18 +1,42 @@
|
|
1
1
|
const { concat } = require("../prettier");
|
2
|
-
const { makeList } = require("../utils");
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
return concat(parts);
|
3
|
+
function isStringContent(node) {
|
4
|
+
return node.type === "@tstring_content";
|
5
|
+
}
|
6
|
+
|
7
|
+
function shouldUseBraces(node) {
|
8
|
+
const first = node.body[0];
|
9
|
+
|
10
|
+
// If the first part of this regex is plain string content and we have a
|
11
|
+
// space or an =, then we want to use braces because otherwise we could end up
|
12
|
+
// with an ambiguous operator, e.g. foo / bar/ or foo /=bar/
|
13
|
+
if (first && isStringContent(first) && [" ", "="].includes(first.body[0])) {
|
14
|
+
return true;
|
17
15
|
}
|
16
|
+
|
17
|
+
return node.body.some(
|
18
|
+
(child) => isStringContent(child) && child.body.includes("/")
|
19
|
+
);
|
20
|
+
}
|
21
|
+
|
22
|
+
// This function is responsible for printing out regexp_literal nodes. They can
|
23
|
+
// either use the special %r literal syntax or they can use forward slashes. At
|
24
|
+
// the end of either of those they can have modifiers like m or x that have
|
25
|
+
// special meaning for the regex engine.
|
26
|
+
//
|
27
|
+
// We favor the use of forward slashes unless the regex contains a forward slash
|
28
|
+
// itself. In that case we switch over to using %r with braces.
|
29
|
+
function printRegexpLiteral(path, opts, print) {
|
30
|
+
const node = path.getValue();
|
31
|
+
const useBraces = shouldUseBraces(node);
|
32
|
+
|
33
|
+
const parts = [useBraces ? "%r{" : "/"]
|
34
|
+
.concat(path.map(print, "body"))
|
35
|
+
.concat([useBraces ? "}" : "/", node.ending.slice(1)]);
|
36
|
+
|
37
|
+
return concat(parts);
|
38
|
+
}
|
39
|
+
|
40
|
+
module.exports = {
|
41
|
+
regexp_literal: printRegexpLiteral
|
18
42
|
};
|
data/src/nodes/rescue.js
CHANGED
@@ -9,73 +9,86 @@ const {
|
|
9
9
|
} = require("../prettier");
|
10
10
|
const { literal } = require("../utils");
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
ensure: (path, opts, print) =>
|
21
|
-
concat([
|
22
|
-
"ensure",
|
23
|
-
indent(concat([hardline, concat(path.map(print, "body"))]))
|
24
|
-
]),
|
25
|
-
redo: literal("redo"),
|
26
|
-
rescue: (path, opts, print) => {
|
27
|
-
const [exception, variable, _stmts, addition] = path.getValue().body;
|
28
|
-
const parts = ["rescue"];
|
12
|
+
function printBegin(path, opts, print) {
|
13
|
+
return concat([
|
14
|
+
"begin",
|
15
|
+
indent(concat([hardline, concat(path.map(print, "body"))])),
|
16
|
+
hardline,
|
17
|
+
"end"
|
18
|
+
]);
|
19
|
+
}
|
29
20
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
} else {
|
37
|
-
// Here we have multiple exceptions from which we're rescuing, so we
|
38
|
-
// need to align them and join them together.
|
39
|
-
const joiner = concat([",", line]);
|
40
|
-
const exceptions = group(join(joiner, path.call(print, "body", 0)));
|
21
|
+
function printEnsure(path, opts, print) {
|
22
|
+
return concat([
|
23
|
+
path.call(print, "body", 0),
|
24
|
+
indent(concat([hardline, path.call(print, "body", 1)]))
|
25
|
+
]);
|
26
|
+
}
|
41
27
|
|
42
|
-
|
43
|
-
|
44
|
-
|
28
|
+
function printRescue(path, opts, print) {
|
29
|
+
const [exception, variable, _stmts, addition] = path.getValue().body;
|
30
|
+
const parts = ["rescue"];
|
31
|
+
|
32
|
+
if (exception || variable) {
|
33
|
+
if (exception) {
|
34
|
+
if (Array.isArray(exception)) {
|
35
|
+
// In this case, it's actually only the one exception (it's an array
|
36
|
+
// of length 1).
|
37
|
+
parts.push(" ", path.call(print, "body", 0, 0));
|
38
|
+
} else {
|
39
|
+
// Here we have multiple exceptions from which we're rescuing, so we
|
40
|
+
// need to align them and join them together.
|
41
|
+
const joiner = concat([",", line]);
|
42
|
+
const exceptions = group(join(joiner, path.call(print, "body", 0)));
|
45
43
|
|
46
|
-
|
47
|
-
parts.push(" => ", path.call(print, "body", 1));
|
44
|
+
parts.push(" ", align("rescue ".length, exceptions));
|
48
45
|
}
|
49
|
-
} else {
|
50
|
-
// If you don't specify an error to rescue in a `begin/rescue` block, then
|
51
|
-
// implicitly you're rescuing from `StandardError`. In this case, we're
|
52
|
-
// just going to explicitly add it.
|
53
|
-
parts.push(" StandardError");
|
54
46
|
}
|
55
47
|
|
56
|
-
|
57
|
-
|
58
|
-
if (rescueBody.parts.length > 0) {
|
59
|
-
parts.push(indent(concat([hardline, rescueBody])));
|
48
|
+
if (variable) {
|
49
|
+
parts.push(" => ", path.call(print, "body", 1));
|
60
50
|
}
|
51
|
+
} else {
|
52
|
+
// If you don't specify an error to rescue in a `begin/rescue` block, then
|
53
|
+
// implicitly you're rescuing from `StandardError`. In this case, we're
|
54
|
+
// just going to explicitly add it.
|
55
|
+
parts.push(" StandardError");
|
56
|
+
}
|
61
57
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
58
|
+
const rescueBody = path.call(print, "body", 2);
|
59
|
+
|
60
|
+
if (rescueBody.parts.length > 0) {
|
61
|
+
parts.push(indent(concat([hardline, rescueBody])));
|
62
|
+
}
|
67
63
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
concat([
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
64
|
+
// This is the next clause on the `begin` statement, either another
|
65
|
+
// `rescue`, and `ensure`, or an `else` clause.
|
66
|
+
if (addition) {
|
67
|
+
parts.push(concat([hardline, path.call(print, "body", 3)]));
|
68
|
+
}
|
69
|
+
|
70
|
+
return group(concat(parts));
|
71
|
+
}
|
72
|
+
|
73
|
+
function printRescueMod(path, opts, print) {
|
74
|
+
const [statementDoc, valueDoc] = path.map(print, "body");
|
75
|
+
|
76
|
+
return concat([
|
77
|
+
"begin",
|
78
|
+
indent(concat([hardline, statementDoc])),
|
79
|
+
hardline,
|
80
|
+
"rescue StandardError",
|
81
|
+
indent(concat([hardline, valueDoc])),
|
82
|
+
hardline,
|
83
|
+
"end"
|
84
|
+
]);
|
85
|
+
}
|
86
|
+
|
87
|
+
module.exports = {
|
88
|
+
begin: printBegin,
|
89
|
+
ensure: printEnsure,
|
90
|
+
redo: literal("redo"),
|
91
|
+
rescue: printRescue,
|
92
|
+
rescue_mod: printRescueMod,
|
80
93
|
retry: literal("retry")
|
81
94
|
};
|
data/src/nodes/statements.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
const {
|
2
|
+
breakParent,
|
2
3
|
concat,
|
3
4
|
dedent,
|
4
5
|
group,
|
@@ -11,63 +12,104 @@ const {
|
|
11
12
|
trim
|
12
13
|
} = require("../prettier");
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
return concat([trim, "__END__", literalline, body]);
|
18
|
-
},
|
19
|
-
bodystmt: (path, opts, print) => {
|
20
|
-
const [_statements, rescue, elseClause, ensure] = path.getValue().body;
|
21
|
-
const parts = [path.call(print, "body", 0)];
|
15
|
+
function printBodyStmt(path, opts, print) {
|
16
|
+
const [stmts, rescue, elseClause, ensure] = path.getValue().body;
|
17
|
+
const parts = [];
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
if (
|
20
|
+
stmts.body.length > 1 ||
|
21
|
+
stmts.body[0].type != "void_stmt" ||
|
22
|
+
stmts.body[0].comments
|
23
|
+
) {
|
24
|
+
parts.push(path.call(print, "body", 0));
|
25
|
+
}
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
elseClause.type === "else"
|
31
|
-
? path.call(print, "body", 2, "body", 0)
|
32
|
-
: path.call(print, "body", 2);
|
27
|
+
if (rescue) {
|
28
|
+
parts.push(dedent(concat([hardline, path.call(print, "body", 1)])));
|
29
|
+
}
|
33
30
|
|
34
|
-
|
35
|
-
|
31
|
+
if (elseClause) {
|
32
|
+
// Before Ruby 2.6, this piece of bodystmt was an explicit "else" node
|
33
|
+
const stmts =
|
34
|
+
elseClause.type === "else"
|
35
|
+
? path.call(print, "body", 2, "body", 0)
|
36
|
+
: path.call(print, "body", 2);
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
}
|
38
|
+
parts.push(concat([dedent(concat([hardline, "else"])), hardline, stmts]));
|
39
|
+
}
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
paren: (path, opts, print) => {
|
45
|
-
if (!path.getValue().body[0]) {
|
46
|
-
return "()";
|
47
|
-
}
|
41
|
+
if (ensure) {
|
42
|
+
parts.push(dedent(concat([hardline, path.call(print, "body", 3)])));
|
43
|
+
}
|
48
44
|
|
49
|
-
|
45
|
+
return group(concat(parts));
|
46
|
+
}
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
) {
|
56
|
-
content = join(concat([",", line]), content);
|
57
|
-
}
|
48
|
+
const argNodeTypes = ["args", "args_add_star", "args_add_block"];
|
49
|
+
|
50
|
+
function printParen(path, opts, print) {
|
51
|
+
const contentNode = path.getValue().body[0];
|
58
52
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
+
|
80
|
+
module.exports = {
|
81
|
+
"@__end__": (path, _opts, _print) => {
|
82
|
+
const { body } = path.getValue();
|
83
|
+
return concat([trim, "__END__", literalline, body]);
|
66
84
|
},
|
85
|
+
bodystmt: printBodyStmt,
|
86
|
+
paren: printParen,
|
67
87
|
program: (path, opts, print) =>
|
68
88
|
concat([join(hardline, path.map(print, "body")), hardline]),
|
69
89
|
stmts: (path, opts, print) => {
|
70
90
|
const stmts = path.getValue().body;
|
91
|
+
|
92
|
+
// This is a special case where we have only comments inside a statement
|
93
|
+
// list. In this case we want to avoid doing any kind of line number
|
94
|
+
// tracking and just print out the comments.
|
95
|
+
if (
|
96
|
+
stmts.length === 1 &&
|
97
|
+
stmts[0].type === "void_stmt" &&
|
98
|
+
stmts[0].comments
|
99
|
+
) {
|
100
|
+
const comments = path.map(
|
101
|
+
(commentPath, index) => {
|
102
|
+
stmts[0].comments[index].printed = true;
|
103
|
+
return opts.printer.printComment(commentPath);
|
104
|
+
},
|
105
|
+
"body",
|
106
|
+
0,
|
107
|
+
"comments"
|
108
|
+
);
|
109
|
+
|
110
|
+
return concat([breakParent, join(hardline, comments)]);
|
111
|
+
}
|
112
|
+
|
71
113
|
const parts = [];
|
72
114
|
let lineNo = null;
|
73
115
|
|
data/src/nodes/strings.js
CHANGED
@@ -8,30 +8,30 @@ const {
|
|
8
8
|
join
|
9
9
|
} = require("../prettier");
|
10
10
|
|
11
|
-
const { concatBody, empty, makeList, prefix, surround } = require("../utils");
|
12
|
-
|
13
11
|
// If there is some part of this string that matches an escape sequence or that
|
14
12
|
// contains the interpolation pattern ("#{"), then we are locked into whichever
|
15
13
|
// quote the user chose. (If they chose single quotes, then double quoting
|
16
14
|
// would activate the escape sequence, and if they chose double quotes, then
|
17
15
|
// single quotes would deactivate it.)
|
18
|
-
|
19
|
-
|
16
|
+
function isQuoteLocked(node) {
|
17
|
+
return node.body.some(
|
20
18
|
(part) =>
|
21
19
|
part.type === "@tstring_content" &&
|
22
20
|
(part.body.includes("#{") || part.body.includes("\\"))
|
23
21
|
);
|
22
|
+
}
|
24
23
|
|
25
24
|
// A string is considered to be able to use single quotes if it contains only
|
26
25
|
// plain string content and that content does not contain a single quote.
|
27
|
-
|
28
|
-
|
26
|
+
function isSingleQuotable(node) {
|
27
|
+
return node.body.every(
|
29
28
|
(part) => part.type === "@tstring_content" && !part.body.includes("'")
|
30
29
|
);
|
30
|
+
}
|
31
31
|
|
32
32
|
const quotePattern = new RegExp("\\\\([\\s\\S])|(['\"])", "g");
|
33
33
|
|
34
|
-
|
34
|
+
function normalizeQuotes(content, enclosingQuote, originalQuote) {
|
35
35
|
const replaceOther = ["'", '"'].includes(originalQuote);
|
36
36
|
const otherQuote = enclosingQuote === '"' ? "'" : '"';
|
37
37
|
|
@@ -52,7 +52,7 @@ const normalizeQuotes = (content, enclosingQuote, originalQuote) => {
|
|
52
52
|
|
53
53
|
return `\\${escaped}`;
|
54
54
|
});
|
55
|
-
}
|
55
|
+
}
|
56
56
|
|
57
57
|
const quotePairs = {
|
58
58
|
"(": ")",
|
@@ -61,51 +61,100 @@ const quotePairs = {
|
|
61
61
|
"<": ">"
|
62
62
|
};
|
63
63
|
|
64
|
-
|
64
|
+
function getClosingQuote(quote) {
|
65
65
|
if (!quote.startsWith("%")) {
|
66
66
|
return quote;
|
67
67
|
}
|
68
68
|
|
69
|
-
const boundary = /%
|
69
|
+
const boundary = /%[Qq]?(.)/.exec(quote)[1];
|
70
70
|
if (boundary in quotePairs) {
|
71
71
|
return quotePairs[boundary];
|
72
72
|
}
|
73
73
|
|
74
74
|
return boundary;
|
75
|
-
}
|
75
|
+
}
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
// Prints a @CHAR node. @CHAR nodes are special character strings that usually
|
78
|
+
// are strings of length 1. If they're any longer than we'll try to apply the
|
79
|
+
// correct quotes.
|
80
|
+
function printChar(path, { rubySingleQuote }, _print) {
|
81
|
+
const { body } = path.getValue();
|
82
|
+
|
83
|
+
if (body.length !== 2) {
|
84
|
+
return body;
|
85
|
+
}
|
86
|
+
|
87
|
+
const quote = rubySingleQuote ? "'" : '"';
|
88
|
+
return concat([quote, body.slice(1), quote]);
|
89
|
+
}
|
90
|
+
|
91
|
+
// Prints a dynamic symbol. Assumes there's a quote property attached to the
|
92
|
+
// node that will tell us which quote to use when printing. We're just going to
|
93
|
+
// use whatever quote was provided.
|
94
|
+
function printDynaSymbol(path, opts, print) {
|
95
|
+
const { quote } = path.getValue();
|
96
|
+
|
97
|
+
return concat([":", quote].concat(path.map(print, "body")).concat(quote));
|
98
|
+
}
|
99
|
+
|
100
|
+
// Prints out an interpolated variable in the string by converting it into an
|
101
|
+
// embedded expression.
|
102
|
+
function printStringDVar(path, opts, print) {
|
103
|
+
return concat(["#{", path.call(print, "body", 0), "}"]);
|
104
|
+
}
|
105
|
+
|
106
|
+
// Prints out a literal string. This function does its best to respect the
|
107
|
+
// wishes of the user with regards to single versus double quotes, but if the
|
108
|
+
// string contains any escape expressions then it will just keep the original
|
109
|
+
// quotes.
|
110
|
+
function printStringLiteral(path, { rubySingleQuote }, print) {
|
111
|
+
const node = path.getValue();
|
112
|
+
|
113
|
+
// If the string is empty, it will not have any parts, so just print out the
|
114
|
+
// quotes corresponding to the config
|
115
|
+
if (node.body.length === 0) {
|
116
|
+
return rubySingleQuote ? "''" : '""';
|
117
|
+
}
|
118
|
+
|
119
|
+
// Determine the quote that should enclose the new string
|
120
|
+
let quote;
|
121
|
+
if (isQuoteLocked(node)) {
|
122
|
+
quote = node.quote;
|
123
|
+
} else {
|
124
|
+
quote = rubySingleQuote && isSingleQuotable(node) ? "'" : '"';
|
125
|
+
}
|
80
126
|
|
81
|
-
|
82
|
-
|
127
|
+
const parts = node.body.map((part, index) => {
|
128
|
+
if (part.type !== "@tstring_content") {
|
129
|
+
// In this case, the part of the string is an embedded expression
|
130
|
+
return path.call(print, "body", index);
|
83
131
|
}
|
84
132
|
|
85
|
-
|
86
|
-
return
|
87
|
-
|
88
|
-
|
89
|
-
|
133
|
+
// In this case, the part of the string is just regular string content
|
134
|
+
return join(
|
135
|
+
literalline,
|
136
|
+
normalizeQuotes(part.body, quote, node.quote).split("\n")
|
137
|
+
);
|
138
|
+
});
|
90
139
|
|
91
|
-
|
92
|
-
|
93
|
-
heredoc: (path, opts, print) => {
|
94
|
-
const { beging, body, ending } = path.getValue();
|
140
|
+
return concat([quote].concat(parts).concat(getClosingQuote(quote)));
|
141
|
+
}
|
95
142
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
143
|
+
// Prints out a symbol literal. Its child will always be the ident that
|
144
|
+
// represents the string content of the symbol.
|
145
|
+
function printSymbolLiteral(path, opts, print) {
|
146
|
+
return concat([":", path.call(print, "body", 0)]);
|
147
|
+
}
|
101
148
|
|
102
|
-
|
103
|
-
|
104
|
-
|
149
|
+
// Prints out an xstring literal. Its child is an array of string parts,
|
150
|
+
// including plain string content and interpolated content.
|
151
|
+
function printXStringLiteral(path, opts, print) {
|
152
|
+
return concat(["`"].concat(path.map(print, "body")).concat("`"));
|
153
|
+
}
|
105
154
|
|
106
|
-
|
107
|
-
|
108
|
-
|
155
|
+
module.exports = {
|
156
|
+
"@CHAR": printChar,
|
157
|
+
dyna_symbol: printDynaSymbol,
|
109
158
|
string_concat: (path, opts, print) =>
|
110
159
|
group(
|
111
160
|
concat([
|
@@ -114,14 +163,15 @@ module.exports = {
|
|
114
163
|
indent(concat([hardline, path.call(print, "body", 1)]))
|
115
164
|
])
|
116
165
|
),
|
117
|
-
string_dvar:
|
166
|
+
string_dvar: printStringDVar,
|
118
167
|
string_embexpr: (path, opts, print) => {
|
119
168
|
const parts = path.call(print, "body", 0);
|
120
169
|
|
121
|
-
// If the interpolated expression is inside of
|
122
|
-
// that gets sent to the command line) then we don't want
|
123
|
-
// indent, as this can lead to some very odd looking
|
124
|
-
|
170
|
+
// If the interpolated expression is inside of a heredoc or an xstring
|
171
|
+
// literal (a string that gets sent to the command line) then we don't want
|
172
|
+
// to automatically indent, as this can lead to some very odd looking
|
173
|
+
// expressions
|
174
|
+
if (["heredoc", "xstring_literal"].includes(path.getParentNode().type)) {
|
125
175
|
return concat(["#{", parts, "}"]);
|
126
176
|
}
|
127
177
|
|
@@ -129,53 +179,7 @@ module.exports = {
|
|
129
179
|
concat(["#{", indent(concat([softline, parts])), concat([softline, "}"])])
|
130
180
|
);
|
131
181
|
},
|
132
|
-
string_literal:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
// If this string is actually a heredoc, bail out and return to the print
|
137
|
-
// function for heredocs
|
138
|
-
if (string.type === "heredoc") {
|
139
|
-
return path.call(print, "body", 0);
|
140
|
-
}
|
141
|
-
|
142
|
-
// If the string is empty, it will not have any parts, so just print out the
|
143
|
-
// quotes corresponding to the config
|
144
|
-
if (string.body.length === 0) {
|
145
|
-
return preferSingleQuotes ? "''" : '""';
|
146
|
-
}
|
147
|
-
|
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
|
-
}
|
155
|
-
|
156
|
-
const parts = string.body.map((part, index) => {
|
157
|
-
if (part.type !== "@tstring_content") {
|
158
|
-
// In this case, the part of the string is an embedded expression
|
159
|
-
return path.call(print, "body", 0, "body", index);
|
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
|
-
);
|
167
|
-
});
|
168
|
-
|
169
|
-
return concat([quote].concat(parts).concat(getClosingQuote(quote)));
|
170
|
-
},
|
171
|
-
symbol: prefix(":"),
|
172
|
-
symbol_literal: concatBody,
|
173
|
-
word_add: concatBody,
|
174
|
-
word_new: empty,
|
175
|
-
xstring: makeList,
|
176
|
-
xstring_literal: (path, opts, print) => {
|
177
|
-
const parts = path.call(print, "body", 0);
|
178
|
-
|
179
|
-
return concat(["`"].concat(parts).concat("`"));
|
180
|
-
}
|
182
|
+
string_literal: printStringLiteral,
|
183
|
+
symbol_literal: printSymbolLiteral,
|
184
|
+
xstring_literal: printXStringLiteral
|
181
185
|
};
|