prettier 0.17.0 β 0.18.0
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 +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,
|