prettier 0.17.0 β 0.18.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 +329 -201
- data/CONTRIBUTING.md +1 -1
- data/README.md +21 -12
- data/package.json +6 -6
- data/src/haml/nodes/silentScript.js +32 -3
- data/src/haml/nodes/tag.js +1 -1
- data/src/haml/parse.rb +2 -0
- data/src/nodes/args.js +7 -0
- data/src/nodes/blocks.js +2 -3
- data/src/nodes/calls.js +1 -1
- data/src/nodes/commands.js +1 -1
- data/src/nodes/conditionals.js +11 -9
- data/src/nodes/ints.js +1 -1
- data/src/nodes/loops.js +16 -0
- data/src/nodes/params.js +3 -1
- data/src/nodes/strings.js +50 -73
- data/src/parse.js +8 -4
- data/src/ripper.rb +29 -21
- metadata +7 -8
- data/src/escapePattern.js +0 -45
data/CONTRIBUTING.md
CHANGED
@@ -107,7 +107,7 @@ Once every node has been printed like the `binary` node above, the `print` node
|
|
107
107
|
|
108
108
|
### Doc to text
|
109
109
|
|
110
|
-
At this point, this is where `prettier`'s printer takes over. Because the remainder of the process is language-agnostic and `prettier` knows how to handle its own `Doc` representation, the Ruby plugin
|
110
|
+
At this point, this is where `prettier`'s printer takes over. Because the remainder of the process is language-agnostic and `prettier` knows how to handle its own `Doc` representation, the Ruby plugin no longer has a job to do. `prettier` will walk its own `Doc` nodes and print them out according to the rules established by the structure.
|
111
111
|
|
112
112
|
## FAQ
|
113
113
|
|
data/README.md
CHANGED
@@ -8,8 +8,8 @@
|
|
8
8
|
<a href="https://gitter.im/jlongster/prettier">
|
9
9
|
<img alt="Gitter" src="https://img.shields.io/gitter/room/jlongster/prettier.svg?style=flat-square">
|
10
10
|
</a>
|
11
|
-
<a href="https://
|
12
|
-
<img alt="
|
11
|
+
<a href="https://github.com/prettier/plugin-ruby/actions">
|
12
|
+
<img alt="GitHub Actions" src="https://img.shields.io/github/workflow/status/prettier/plugin-ruby/Main?style=flat-square">
|
13
13
|
</a>
|
14
14
|
<a href="https://www.npmjs.com/package/@prettier/plugin-ruby">
|
15
15
|
<img alt="NPM Version" src="https://img.shields.io/npm/v/@prettier/plugin-ruby.svg?style=flat-square">
|
@@ -120,16 +120,16 @@ The `prettier` executable is now installed and ready for use:
|
|
120
120
|
|
121
121
|
Below are the options (from [`src/ruby.js`](src/ruby.js)) that `@prettier/plugin-ruby` currently supports:
|
122
122
|
|
123
|
-
|
|
124
|
-
| -------------------- | :-----: | ------------------------------------------------------------------------------------------------------------- |
|
125
|
-
| `printWidth` | `80` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#print-width)). |
|
126
|
-
| `requirePragma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#require-pragma)). |
|
127
|
-
| `tabWidth` | `2` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#tab-width)). |
|
128
|
-
| `addTrailingCommas` | `false` | Adds a trailing comma to array literals, hash literals, and method calls. |
|
129
|
-
| `inlineConditionals` | `true` | When it fits on one line, allows if and unless statements to use the modifier form. |
|
130
|
-
| `inlineLoops` | `true` | When it fits on one line, allows while and until statements to use the modifier form. |
|
131
|
-
| `preferHashLabels` | `true` | When possible, uses the shortened hash key syntax, as opposed to hash rockets. |
|
132
|
-
| `preferSingleQuotes` | `true` | When double quotes are not necessary for interpolation, prefers the use of single quotes for string literals. |
|
123
|
+
| API Option | CLI Option | Default | Description |
|
124
|
+
| -------------------- | ------------------------ | :-----: | ------------------------------------------------------------------------------------------------------------- |
|
125
|
+
| `printWidth` | `--print-width` | `80` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#print-width)). |
|
126
|
+
| `requirePragma` | `--require-pragma` | `false` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#require-pragma)). |
|
127
|
+
| `tabWidth` | `--tab-width` | `2` | Same as in Prettier ([see prettier docs](https://prettier.io/docs/en/options.html#tab-width)). |
|
128
|
+
| `addTrailingCommas` | `--add-trailing-commas` | `false` | Adds a trailing comma to array literals, hash literals, and method calls. |
|
129
|
+
| `inlineConditionals` | `--inline-conditionals` | `true` | When it fits on one line, allows if and unless statements to use the modifier form. |
|
130
|
+
| `inlineLoops` | `--inline-loops` | `true` | When it fits on one line, allows while and until statements to use the modifier form. |
|
131
|
+
| `preferHashLabels` | `--prefer-hash-labels` | `true` | When possible, uses the shortened hash key syntax, as opposed to hash rockets. |
|
132
|
+
| `preferSingleQuotes` | `--prefer-single-quotes` | `true` | When double quotes are not necessary for interpolation, prefers the use of single quotes for string literals. |
|
133
133
|
|
134
134
|
Any of these can be added to your existing [prettier configuration
|
135
135
|
file](https://prettier.io/docs/en/configuration.html). For example:
|
@@ -199,6 +199,15 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|
199
199
|
<td align="center"><a href="http://vesalaakso.com"><img src="https://avatars2.githubusercontent.com/u/482561?v=4" width="100px;" alt=""/><br /><sub><b>Vesa Laakso</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/commits?author=valscion" title="Documentation">π</a></td>
|
200
200
|
<td align="center"><a href="https://github.com/jrdioko"><img src="https://avatars0.githubusercontent.com/u/405288?v=4" width="100px;" alt=""/><br /><sub><b>jrdioko</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Ajrdioko" title="Bug reports">π</a></td>
|
201
201
|
<td align="center"><a href="http://gin0606.hatenablog.com"><img src="https://avatars2.githubusercontent.com/u/795891?v=4" width="100px;" alt=""/><br /><sub><b>gin0606</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Agin0606" title="Bug reports">π</a> <a href="https://github.com/prettier/plugin-ruby/commits?author=gin0606" title="Code">π»</a></td>
|
202
|
+
<td align="center"><a href="https://github.com/tobyndockerill"><img src="https://avatars1.githubusercontent.com/u/5688326?v=4" width="100px;" alt=""/><br /><sub><b>Tobyn</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/commits?author=tobyndockerill" title="Code">π»</a></td>
|
203
|
+
<td align="center"><a href="http://ianks.com"><img src="https://avatars0.githubusercontent.com/u/3303032?v=4" width="100px;" alt=""/><br /><sub><b>Ian Ker-Seymer</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/commits?author=ianks" title="Code">π»</a></td>
|
204
|
+
<td align="center"><a href="https://huangzhimin.com"><img src="https://avatars2.githubusercontent.com/u/66836?v=4" width="100px;" alt=""/><br /><sub><b>Richard Huang</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/commits?author=flyerhzm" title="Code">π»</a></td>
|
205
|
+
</tr>
|
206
|
+
<tr>
|
207
|
+
<td align="center"><a href="https://github.com/pje"><img src="https://avatars1.githubusercontent.com/u/319655?v=4" width="100px;" alt=""/><br /><sub><b>Patrick Ellis</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Apje" title="Bug reports">π</a></td>
|
208
|
+
<td align="center"><a href="https://www.piesync.com/"><img src="https://avatars0.githubusercontent.com/u/161271?v=4" width="100px;" alt=""/><br /><sub><b>Peter De Berdt</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Amasqita" title="Bug reports">π</a></td>
|
209
|
+
<td align="center"><a href="https://github.com/hafley66"><img src="https://avatars0.githubusercontent.com/u/6750483?v=4" width="100px;" alt=""/><br /><sub><b>Chris Hafley</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3Ahafley66" title="Bug reports">π</a></td>
|
210
|
+
<td align="center"><a href="http://fruetel.de"><img src="https://avatars1.githubusercontent.com/u/8015212?v=4" width="100px;" alt=""/><br /><sub><b>Thomas FrΓΌtel</b></sub></a><br /><a href="https://github.com/prettier/plugin-ruby/issues?q=author%3AFruetel" title="Bug reports">π</a></td>
|
202
211
|
</tr>
|
203
212
|
</table>
|
204
213
|
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@prettier/plugin-ruby",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.18.0",
|
4
4
|
"description": "prettier plugin for the Ruby programming language",
|
5
5
|
"main": "src/ruby.js",
|
6
6
|
"scripts": {
|
@@ -22,12 +22,12 @@
|
|
22
22
|
"prettier": ">=1.10"
|
23
23
|
},
|
24
24
|
"devDependencies": {
|
25
|
-
"all-contributors-cli": "^6.
|
26
|
-
"eslint": "^6.0
|
25
|
+
"all-contributors-cli": "^6.12.0",
|
26
|
+
"eslint": "^6.8.0",
|
27
27
|
"eslint-config-airbnb-base": "^14.0.0",
|
28
|
-
"eslint-config-prettier": "^6.
|
29
|
-
"eslint-plugin-import": "^2.
|
30
|
-
"jest": "^
|
28
|
+
"eslint-config-prettier": "^6.9.0",
|
29
|
+
"eslint-plugin-import": "^2.20.0",
|
30
|
+
"jest": "^25.1.0"
|
31
31
|
},
|
32
32
|
"jest": {
|
33
33
|
"setupFilesAfterEnv": [
|
@@ -1,5 +1,21 @@
|
|
1
1
|
const { concat, group, hardline, indent, join } = require("../../prettier");
|
2
2
|
|
3
|
+
const findKeywordIndices = (children, keywords) => {
|
4
|
+
const indices = [];
|
5
|
+
|
6
|
+
children.forEach((child, index) => {
|
7
|
+
if (child.type !== "silent_script") {
|
8
|
+
return;
|
9
|
+
}
|
10
|
+
|
11
|
+
if (keywords.includes(child.value.keyword)) {
|
12
|
+
indices.push(index);
|
13
|
+
}
|
14
|
+
});
|
15
|
+
|
16
|
+
return indices;
|
17
|
+
};
|
18
|
+
|
3
19
|
// http://haml.info/docs/yardoc/file.REFERENCE.html#running-ruby--
|
4
20
|
const silentScript = (path, opts, print) => {
|
5
21
|
const { children, value } = path.getValue();
|
@@ -9,13 +25,26 @@ const silentScript = (path, opts, print) => {
|
|
9
25
|
const scripts = path.map(print, "children");
|
10
26
|
|
11
27
|
if (value.keyword === "case") {
|
28
|
+
const keywordIndices = findKeywordIndices(children, ["when", "else"]);
|
29
|
+
|
30
|
+
parts.push(
|
31
|
+
concat(
|
32
|
+
scripts.map((script, index) => {
|
33
|
+
const concated = concat([hardline, script]);
|
34
|
+
|
35
|
+
return keywordIndices.includes(index) ? concated : indent(concated);
|
36
|
+
})
|
37
|
+
)
|
38
|
+
);
|
39
|
+
} else if (["if", "unless"].includes(value.keyword)) {
|
40
|
+
const keywordIndices = findKeywordIndices(children, ["elsif", "else"]);
|
41
|
+
|
12
42
|
parts.push(
|
13
|
-
|
14
|
-
"",
|
43
|
+
concat(
|
15
44
|
scripts.map((script, index) => {
|
16
45
|
const concated = concat([hardline, script]);
|
17
46
|
|
18
|
-
return index
|
47
|
+
return keywordIndices.includes(index) ? concated : indent(concated);
|
19
48
|
})
|
20
49
|
)
|
21
50
|
);
|
data/src/haml/nodes/tag.js
CHANGED
data/src/haml/parse.rb
CHANGED
data/src/nodes/args.js
CHANGED
@@ -17,6 +17,13 @@ module.exports = {
|
|
17
17
|
return "";
|
18
18
|
}
|
19
19
|
|
20
|
+
// Here we can skip the entire rest of the method by just checking if it's
|
21
|
+
// an args_forward node, as we're guaranteed that there are no other arg
|
22
|
+
// nodes.
|
23
|
+
if (path.getValue().body[0].type === "args_forward") {
|
24
|
+
return "(...)";
|
25
|
+
}
|
26
|
+
|
20
27
|
const { addTrailingCommas } = opts;
|
21
28
|
const { args, heredocs } = makeArgs(path, opts, print, 0);
|
22
29
|
|
data/src/nodes/blocks.js
CHANGED
@@ -8,7 +8,7 @@ const {
|
|
8
8
|
removeLines,
|
9
9
|
softline
|
10
10
|
} = require("../prettier");
|
11
|
-
const { empty,
|
11
|
+
const { empty, hasAncestor } = require("../utils");
|
12
12
|
|
13
13
|
const printBlock = (path, opts, print) => {
|
14
14
|
const [variables, statements] = path.getValue().body;
|
@@ -76,6 +76,5 @@ module.exports = {
|
|
76
76
|
},
|
77
77
|
brace_block: printBlock,
|
78
78
|
do_block: printBlock,
|
79
|
-
excessed_comma: empty
|
80
|
-
number_arg: first
|
79
|
+
excessed_comma: empty
|
81
80
|
};
|
data/src/nodes/calls.js
CHANGED
data/src/nodes/commands.js
CHANGED
@@ -5,7 +5,7 @@ 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:
|
data/src/nodes/conditionals.js
CHANGED
@@ -75,20 +75,17 @@ 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
91
|
stmts.type === "stmts" && stmts.body.some(stmt => stmt.type === "@comment");
|
@@ -230,7 +227,12 @@ const printConditional = keyword => (path, { inlineConditionals }, print) => {
|
|
230
227
|
// know for sure that it doesn't impact the body of the conditional, so we
|
231
228
|
// have to default to the block form.
|
232
229
|
if (containsAssignment(predicate)) {
|
233
|
-
return
|
230
|
+
return concat([
|
231
|
+
`${keyword} `,
|
232
|
+
align(keyword.length + 1, path.call(print, "body", 0)),
|
233
|
+
indent(concat([hardline, path.call(print, "body", 1)])),
|
234
|
+
concat([hardline, "end"])
|
235
|
+
]);
|
234
236
|
}
|
235
237
|
|
236
238
|
return printSingle(keyword)(path, { inlineConditionals }, print);
|
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/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/params.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
const { concat, group, join, line } = require("../prettier");
|
2
|
+
const { literal } = require("../utils");
|
2
3
|
|
3
4
|
const printGenericRestParam = symbol => (path, opts, print) =>
|
4
5
|
path.getValue().body[0]
|
@@ -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/strings.js
CHANGED
@@ -7,8 +7,8 @@ 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
|
@@ -19,7 +19,7 @@ const isQuoteLocked = string =>
|
|
19
19
|
string.body.some(
|
20
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
|
@@ -29,17 +29,9 @@ const isSingleQuotable = string =>
|
|
29
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,
|