Add Doc[] as Doc (#9733)
Co-authored-by: Georgii Dolzhykov <thorn.mailbox@gmail.com>
This commit is contained in:
1 parent
23521ded6c
commit
9d9c0e2b6f
22 files changed
+332
-93
No files matched your search
@@ -109,8 +109,12 @@ overrides:
|
||||
prettier-internal-rules/better-parent-property-check-in-needs-parens: error
|
||||
- files: src/**/*.js
|
||||
rules:
|
||||
prettier-internal-rules/no-doc-builder-concat: off
|
||||
prettier-internal-rules/prefer-fast-path-each: error
|
||||
prettier-internal-rules/prefer-is-non-empty-array: error
|
||||
- files: src/document/*.js
|
||||
rules:
|
||||
prettier-internal-rules/no-doc-builder-concat: off
|
||||
- files:
|
||||
- src/language-*/**/*.js
|
||||
rules:
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#### Use arrays instead of `concat` (#9733 by @fisker, @thorn0)
|
||||
|
||||
To simplify the code of AST printers, the data structure for the concatenation command has been changed from `{ type: 'concat', parts: Doc[] }` to `Doc[]`. The old format is deprecated, but for compatibility, the doc printer still supports it, and `doc.builders.concat` (as well as some other builder functions) will keep using it until the next major version of Prettier.
|
||||
|
||||
If you're a plugin author, this change should only concern you if your plugin introspects or modifies composed docs. If it happens to be the case, please make your plugin compatible with future versions of Prettier by tweaking the introspecting code to support the new format. There also is an off-chance where this change can break things, namely if a plugin calls another plugin to [print an embedded language](https://prettier.io/docs/en/plugins.html#optional-embed) and then introspects the returned doc. There seems to be no reason for plugins to do that though.
|
||||
|
||||
```jsx
|
||||
// Prettier stable
|
||||
myDoc = group(concat(["foo", line, "bar"]));
|
||||
|
||||
// Prettier master
|
||||
myDoc = group(["foo", line, "bar"]);
|
||||
```
|
||||
+18
-16
@@ -2,14 +2,6 @@ The core of the algorithm is implemented in `doc-{printer,builders,utils,debug}.
|
||||
|
||||
The following commands are available:
|
||||
|
||||
### concat
|
||||
|
||||
```ts
|
||||
declare function concat(docs: Doc[]): Doc;
|
||||
```
|
||||
|
||||
Combine an array into a single string.
|
||||
|
||||
### group
|
||||
|
||||
```ts
|
||||
@@ -97,7 +89,7 @@ declare var breakParent: Doc;
|
||||
Include this anywhere to force all parent groups to break. See `group` for more info. Example:
|
||||
|
||||
```js
|
||||
group(concat([" ", expr, " ", breakParent]));
|
||||
group([" ", expr, " ", breakParent]);
|
||||
```
|
||||
|
||||
### join
|
||||
@@ -149,7 +141,7 @@ declare function lineSuffix(suffix: Doc): Doc;
|
||||
This is used to implement trailing comments. In practice, it is not practical to find where the line ends and you don't want to accidentally print some code at the end of the comment. `lineSuffix` will buffer the output and flush it before any new line.
|
||||
|
||||
```js
|
||||
concat(["a", lineSuffix(" // comment"), ";", hardline]);
|
||||
["a", lineSuffix(" // comment"), ";", hardline];
|
||||
```
|
||||
|
||||
will output
|
||||
@@ -167,7 +159,7 @@ declare var lineSuffixBoundary: Doc;
|
||||
In cases where you embed code inside of templates, comments shouldn't be able to leave the code part. lineSuffixBoundary is an explicit marker you can use to flush code in addition to newlines.
|
||||
|
||||
```js
|
||||
concat(["{", lineSuffix(" // comment"), lineSuffixBoundary, "}", hardline]);
|
||||
["{", lineSuffix(" // comment"), lineSuffixBoundary, "}", hardline];
|
||||
```
|
||||
|
||||
will output
|
||||
@@ -260,21 +252,31 @@ For an example, here's the implementation of the `ArrayExpression` node type:
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
group(
|
||||
concat([
|
||||
[
|
||||
"[",
|
||||
indent(
|
||||
concat([
|
||||
[
|
||||
line,
|
||||
join(
|
||||
concat([",", line]),
|
||||
[",", line],
|
||||
path.map(print, "elements")
|
||||
)
|
||||
])
|
||||
]
|
||||
),
|
||||
line,
|
||||
"]"
|
||||
])
|
||||
]
|
||||
);
|
||||
```
|
||||
|
||||
This is a group with opening and closing brackets, and possibly indented contents. Because it's a `group` it will always be broken up if any of the sub-expressions are broken.
|
||||
|
||||
### [Deprecated] concat
|
||||
|
||||
> This command is deprecated, use `Doc[]` instead.
|
||||
|
||||
```ts
|
||||
declare function concat(docs: Doc[]): Doc;
|
||||
```
|
||||
|
||||
Combine an array into a single string.
|
||||
+1
-1
@@ -170,7 +170,7 @@ export const printers = {
|
||||
Prettier uses an intermediate representation, called a Doc, which Prettier then turns into a string (based on options like `printWidth`). A _printer_'s job is to take the AST generated by `parsers[<parser name>].parse` and return a Doc. A Doc is constructed using [builder commands](https://github.com/prettier/prettier/blob/master/commands.md):
|
||||
|
||||
```js
|
||||
const { concat, join, line, ifBreak, group } = require("prettier").doc.builders;
|
||||
const { join, line, ifBreak, group } = require("prettier").doc.builders;
|
||||
```
|
||||
|
||||
The printing process works as follows:
|
||||
|
||||
@@ -7,6 +7,6 @@ This printer is a fork of [recast](https://github.com/benjamn/recast)’s printe
|
||||
|
||||
The basic idea is that the printer takes an AST and returns an intermediate representation of the output, and the printer uses that to generate a string. The advantage is that the printer can "measure" the IR and see if the output is going to fit on a line, and break if not.
|
||||
|
||||
This means that most of the logic of printing an AST involves generating an abstract representation of the output involving certain commands. For example, `concat(["(", line, arg, line, ")"])` would represent a concatenation of opening parens, an argument, and closing parens. But if that doesn’t fit on one line, the printer can break where `line` is specified.
|
||||
This means that most of the logic of printing an AST involves generating an abstract representation of the output involving certain commands. For example, `["(", line, arg, line, ")"]` would represent a concatenation of opening parens, an argument, and closing parens. But if that doesn’t fit on one line, the printer can break where `line` is specified.
|
||||
|
||||
More (rough) details can be found in [commands.md](https://github.com/prettier/prettier/blob/master/commands.md).
|
||||
@@ -5,6 +5,7 @@ module.exports = {
|
||||
"better-parent-property-check-in-needs-parens": require("./better-parent-property-check-in-needs-parens"),
|
||||
"directly-loc-start-end": require("./directly-loc-start-end"),
|
||||
"jsx-identifier-case": require("./jsx-identifier-case"),
|
||||
"no-doc-builder-concat": require("./no-doc-builder-concat"),
|
||||
"no-node-comments": require("./no-node-comments"),
|
||||
"prefer-fast-path-each": require("./prefer-fast-path-each"),
|
||||
"prefer-is-non-empty-array": require("./prefer-is-non-empty-array"),
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
const selector = [
|
||||
"CallExpression",
|
||||
">",
|
||||
"Identifier.callee",
|
||||
'[name="concat"]',
|
||||
].join("");
|
||||
|
||||
const messageId = "no-doc-builder-concat";
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
docs: {
|
||||
url:
|
||||
"https://github.com/prettier/prettier/blob/master/scripts/eslint-plugin-prettier-internal-rules/no-doc-builder-concat.js",
|
||||
},
|
||||
messages: {
|
||||
[messageId]: "Use array directly instead of `concat([])`",
|
||||
},
|
||||
fixable: "code",
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
[selector](node) {
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
fix: (fixer) => fixer.replaceText(node, ""),
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -94,6 +94,22 @@ test("jsx-identifier-case", {
|
||||
],
|
||||
});
|
||||
|
||||
test("no-doc-builder-concat", {
|
||||
valid: ["notConcat([])", "concat", "[].concat([])"],
|
||||
invalid: [
|
||||
{
|
||||
code: "concat(parts)",
|
||||
output: "(parts)",
|
||||
errors: 1,
|
||||
},
|
||||
{
|
||||
code: "concat(['foo', line])",
|
||||
output: "(['foo', line])",
|
||||
errors: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
test("no-node-comments", {
|
||||
valid: [
|
||||
"const comments = node.notComments",
|
||||
|
||||
@@ -8,21 +8,32 @@
|
||||
* @property {boolean} [hard]
|
||||
* @property {boolean} [literal]
|
||||
*
|
||||
* @typedef {string | DocObject} Doc
|
||||
* @typedef {Doc[]} DocArray
|
||||
*
|
||||
* @typedef {string | DocObject | DocArray} Doc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Doc} val
|
||||
*/
|
||||
function assertDoc(val) {
|
||||
/* istanbul ignore if */
|
||||
if (
|
||||
!(typeof val === "string" || (val != null && typeof val.type === "string"))
|
||||
) {
|
||||
throw new Error(
|
||||
"Value " + JSON.stringify(val) + " is not a valid document"
|
||||
);
|
||||
if (typeof val === "string") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
for (const doc of val) {
|
||||
assertDoc(doc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (val && typeof val.type === "string") {
|
||||
return;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
throw new Error("Value " + JSON.stringify(val) + " is not a valid document");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+13
-11
@@ -1,12 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
function flattenDoc(doc) {
|
||||
if (doc.type === "concat") {
|
||||
const res = [];
|
||||
const { isConcat, getDocParts } = require("./doc-utils");
|
||||
|
||||
for (let i = 0; i < doc.parts.length; ++i) {
|
||||
const doc2 = doc.parts[i];
|
||||
if (typeof doc2 !== "string" && doc2.type === "concat") {
|
||||
function flattenDoc(doc) {
|
||||
if (isConcat(doc)) {
|
||||
const res = [];
|
||||
const parts = getDocParts(doc);
|
||||
for (let i = 0; i < parts.length; ++i) {
|
||||
const doc2 = parts[i];
|
||||
if (typeof doc2 !== "string" && isConcat(doc2)) {
|
||||
res.push(...flattenDoc(doc2).parts);
|
||||
} else {
|
||||
const flattened = flattenDoc(doc2);
|
||||
@@ -16,7 +18,7 @@ function flattenDoc(doc) {
|
||||
}
|
||||
}
|
||||
|
||||
return { ...doc, parts: res };
|
||||
return { type: "concat", parts: res };
|
||||
} else if (doc.type === "if-break") {
|
||||
return {
|
||||
...doc,
|
||||
@@ -44,6 +46,10 @@ function printDoc(doc) {
|
||||
return JSON.stringify(doc);
|
||||
}
|
||||
|
||||
if (isConcat(doc)) {
|
||||
return "[" + getDocParts(doc).map(printDoc).join(", ") + "]";
|
||||
}
|
||||
|
||||
if (doc.type === "line") {
|
||||
if (doc.literal) {
|
||||
return "literalline";
|
||||
@@ -65,10 +71,6 @@ function printDoc(doc) {
|
||||
return "trim";
|
||||
}
|
||||
|
||||
if (doc.type === "concat") {
|
||||
return "[" + doc.parts.map(printDoc).join(", ") + "]";
|
||||
}
|
||||
|
||||
if (doc.type === "indent") {
|
||||
return "indent(" + printDoc(doc.contents) + ")";
|
||||
}
|
||||
|
||||
+11
-12
@@ -3,6 +3,7 @@
|
||||
const { getStringWidth } = require("../common/util");
|
||||
const { convertEndOfLineToChars } = require("../common/end-of-line");
|
||||
const { concat, fill, cursor } = require("./doc-builders");
|
||||
const { isConcat, getDocParts } = require("./doc-utils");
|
||||
|
||||
/** @type {Record<symbol, typeof MODE_BREAK | typeof MODE_FLAT>} */
|
||||
let groupModeMap;
|
||||
@@ -167,14 +168,13 @@ function fits(next, restCommands, width, options, mustBeFlat) {
|
||||
out.push(doc);
|
||||
|
||||
width -= getStringWidth(doc);
|
||||
} else if (isConcat(doc)) {
|
||||
const parts = getDocParts(doc);
|
||||
for (let i = parts.length - 1; i >= 0; i--) {
|
||||
cmds.push([ind, mode, parts[i]]);
|
||||
}
|
||||
} else {
|
||||
switch (doc.type) {
|
||||
case "concat":
|
||||
for (let i = doc.parts.length - 1; i >= 0; i--) {
|
||||
cmds.push([ind, mode, doc.parts[i]]);
|
||||
}
|
||||
|
||||
break;
|
||||
case "indent":
|
||||
cmds.push([makeIndent(ind, options), mode, doc.contents]);
|
||||
|
||||
@@ -264,17 +264,16 @@ function printDocToString(doc, options) {
|
||||
const formatted = newLine !== "\n" ? doc.replace(/\n/g, newLine) : doc;
|
||||
out.push(formatted);
|
||||
pos += getStringWidth(formatted);
|
||||
} else if (isConcat(doc)) {
|
||||
const parts = getDocParts(doc);
|
||||
for (let i = parts.length - 1; i >= 0; i--) {
|
||||
cmds.push([ind, mode, parts[i]]);
|
||||
}
|
||||
} else {
|
||||
switch (doc.type) {
|
||||
case "cursor":
|
||||
out.push(cursor.placeholder);
|
||||
|
||||
break;
|
||||
case "concat":
|
||||
for (let i = doc.parts.length - 1; i >= 0; i--) {
|
||||
cmds.push([ind, mode, doc.parts[i]]);
|
||||
}
|
||||
|
||||
break;
|
||||
case "indent":
|
||||
cmds.push([makeIndent(ind, options), mode, doc.contents]);
|
||||
|
||||
+35
-25
@@ -2,6 +2,9 @@
|
||||
|
||||
const { literalline, concat } = require("./doc-builders");
|
||||
|
||||
const isConcat = (doc) => Array.isArray(doc) || (doc && doc.type === "concat");
|
||||
const getDocParts = (doc) => (Array.isArray(doc) ? doc : doc.parts);
|
||||
|
||||
// Using a unique object to compare by reference.
|
||||
const traverseDocOnExitStackMarker = {};
|
||||
|
||||
@@ -29,9 +32,10 @@ function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) {
|
||||
// the parts need to be pushed onto the stack in reverse order,
|
||||
// so that they are processed in the original order
|
||||
// when the stack is popped.
|
||||
if (doc.type === "concat" || doc.type === "fill") {
|
||||
for (let ic = doc.parts.length, i = ic - 1; i >= 0; --i) {
|
||||
docsStack.push(doc.parts[i]);
|
||||
if (isConcat(doc) || doc.type === "fill") {
|
||||
const parts = getDocParts(doc);
|
||||
for (let ic = parts.length, i = ic - 1; i >= 0; --i) {
|
||||
docsStack.push(parts[i]);
|
||||
}
|
||||
} else if (doc.type === "if-break") {
|
||||
if (doc.flatContents) {
|
||||
@@ -56,7 +60,9 @@ function traverseDoc(doc, onEnter, onExit, shouldTraverseConditionalGroups) {
|
||||
}
|
||||
|
||||
function mapDoc(doc, cb) {
|
||||
if (doc.type === "concat" || doc.type === "fill") {
|
||||
if (Array.isArray(doc)) {
|
||||
return cb(doc.map((part) => mapDoc(part, cb)));
|
||||
} else if (doc.type === "concat" || doc.type === "fill") {
|
||||
const parts = doc.parts.map((part) => mapDoc(part, cb));
|
||||
return cb({ ...doc, parts });
|
||||
} else if (doc.type === "if-break") {
|
||||
@@ -191,23 +197,21 @@ function stripDocTrailingHardlineFromDoc(doc) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
switch (doc.type) {
|
||||
case "concat":
|
||||
case "fill": {
|
||||
const parts = [...doc.parts];
|
||||
if (isConcat(doc) || doc.type === "fill") {
|
||||
const parts = getDocParts(doc);
|
||||
|
||||
while (parts.length > 1 && isHardline(...parts.slice(-2))) {
|
||||
parts.length -= 2;
|
||||
}
|
||||
|
||||
if (parts.length > 0) {
|
||||
const lastPart = stripDocTrailingHardlineFromDoc(
|
||||
parts[parts.length - 1]
|
||||
);
|
||||
parts[parts.length - 1] = lastPart;
|
||||
}
|
||||
return { ...doc, parts };
|
||||
while (parts.length > 1 && isHardline(...parts.slice(-2))) {
|
||||
parts.length -= 2;
|
||||
}
|
||||
|
||||
if (parts.length > 0) {
|
||||
const lastPart = stripDocTrailingHardlineFromDoc(parts[parts.length - 1]);
|
||||
parts[parts.length - 1] = lastPart;
|
||||
}
|
||||
return Array.isArray(doc) ? parts : { ...doc, parts };
|
||||
}
|
||||
|
||||
switch (doc.type) {
|
||||
case "align":
|
||||
case "indent":
|
||||
case "group":
|
||||
@@ -230,7 +234,6 @@ function stripTrailingHardline(doc) {
|
||||
return stripDocTrailingHardlineFromDoc(cleanDoc(doc));
|
||||
}
|
||||
|
||||
const isConcat = (doc) => doc && doc.type === "concat";
|
||||
function cleanDocFn(doc) {
|
||||
switch (doc.type) {
|
||||
case "fill":
|
||||
@@ -271,11 +274,13 @@ function cleanDocFn(doc) {
|
||||
}
|
||||
|
||||
const parts = [];
|
||||
for (const part of doc.parts) {
|
||||
for (const part of getDocParts(doc)) {
|
||||
if (!part) {
|
||||
continue;
|
||||
}
|
||||
const [currentPart, ...restParts] = isConcat(part) ? part.parts : [part];
|
||||
const [currentPart, ...restParts] = isConcat(part)
|
||||
? getDocParts(part)
|
||||
: [part];
|
||||
if (
|
||||
typeof currentPart === "string" &&
|
||||
typeof parts[parts.length - 1] === "string"
|
||||
@@ -294,7 +299,7 @@ function cleanDocFn(doc) {
|
||||
if (parts.length === 1) {
|
||||
return parts[0];
|
||||
}
|
||||
return { ...doc, parts };
|
||||
return Array.isArray(doc) ? parts : { ...doc, parts };
|
||||
}
|
||||
// A safer version of `normalizeDoc`
|
||||
// - `normalizeDoc` concat strings and flat "concat" in `fill`, while `cleanDoc` don't
|
||||
@@ -315,8 +320,8 @@ function normalizeParts(parts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part.type === "concat") {
|
||||
restParts.unshift(...part.parts);
|
||||
if (isConcat(part)) {
|
||||
restParts.unshift(...getDocParts(part));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -337,6 +342,9 @@ function normalizeParts(parts) {
|
||||
|
||||
function normalizeDoc(doc) {
|
||||
return mapDoc(doc, (currentDoc) => {
|
||||
if (Array.isArray(currentDoc)) {
|
||||
return normalizeParts(currentDoc);
|
||||
}
|
||||
if (!currentDoc.parts) {
|
||||
return currentDoc;
|
||||
}
|
||||
@@ -360,6 +368,8 @@ function replaceNewlinesWithLiterallines(doc) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isConcat,
|
||||
getDocParts,
|
||||
isEmpty,
|
||||
willBreak,
|
||||
isLineNext,
|
||||
|
||||
@@ -22,7 +22,7 @@ const {
|
||||
ifBreak,
|
||||
breakParent,
|
||||
},
|
||||
utils: { removeLines },
|
||||
utils: { removeLines, getDocParts },
|
||||
} = require("../document");
|
||||
const clean = require("./clean");
|
||||
const embed = require("./embed");
|
||||
@@ -102,7 +102,7 @@ function genericPrint(path, options, print) {
|
||||
return concat([
|
||||
nodes,
|
||||
after ? ` ${after}` : "",
|
||||
nodes.parts.length ? hardline : "",
|
||||
getDocParts(nodes).length ? hardline : "",
|
||||
]);
|
||||
}
|
||||
case "css-comment": {
|
||||
@@ -892,9 +892,8 @@ function genericPrint(path, options, print) {
|
||||
node.groups[2] &&
|
||||
node.groups[2].type === "value-paren_group"
|
||||
) {
|
||||
printed.contents.contents.parts[1] = group(
|
||||
printed.contents.contents.parts[1]
|
||||
);
|
||||
const parts = getDocParts(printed.contents.contents);
|
||||
parts[1] = group(parts[1]);
|
||||
|
||||
return group(dedent(printed));
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const {
|
||||
builders: { concat, group, hardline, ifBreak, indent, join, line, softline },
|
||||
utils: { getDocParts },
|
||||
} = require("../document");
|
||||
const { locStart, locEnd } = require("./loc");
|
||||
const clean = require("./clean");
|
||||
@@ -141,7 +142,7 @@ function print(path, options, print) {
|
||||
}
|
||||
const value = path.call(print, "value");
|
||||
const quotedValue = isText
|
||||
? printStringLiteral(value.parts.join(), options)
|
||||
? printStringLiteral(getDocParts(value).join(), options)
|
||||
: value;
|
||||
return concat([n.name, "=", quotedValue]);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const {
|
||||
softline,
|
||||
concat,
|
||||
},
|
||||
utils: { mapDoc, cleanDoc },
|
||||
utils: { mapDoc, cleanDoc, getDocParts },
|
||||
} = require("../document");
|
||||
const { replaceEndOfLineWith, isNonEmptyArray } = require("../common/util");
|
||||
const { print: printFrontMatter } = require("../utils/front-matter");
|
||||
@@ -378,7 +378,7 @@ function genericPrint(path, options, print) {
|
||||
printClosingTagSuffix(node, options),
|
||||
])
|
||||
);
|
||||
return typeof printed === "string" ? printed : fill(printed.parts);
|
||||
return typeof printed === "string" ? printed : fill(getDocParts(printed));
|
||||
}
|
||||
case "docType":
|
||||
return concat([
|
||||
@@ -981,7 +981,7 @@ function getTextValueParts(node, value = node.value) {
|
||||
dedentString(htmlTrimPreserveIndentation(value)),
|
||||
hardline
|
||||
)
|
||||
: join(line, splitByHtmlWhitespace(value)).parts;
|
||||
: getDocParts(join(line, splitByHtmlWhitespace(value)));
|
||||
}
|
||||
|
||||
function printEmbeddedAttributeValue(node, originalTextToDoc, options) {
|
||||
|
||||
@@ -4,7 +4,7 @@ const { printComments } = require("../../main/comments");
|
||||
const { getLast } = require("../../common/util");
|
||||
const {
|
||||
builders: { concat, join, line, softline, group, indent, align, ifBreak },
|
||||
utils: { cleanDoc },
|
||||
utils: { cleanDoc, getDocParts },
|
||||
} = require("../../document");
|
||||
const {
|
||||
hasLeadingOwnLineComment,
|
||||
@@ -130,7 +130,8 @@ function printBinaryishExpression(path, options, print) {
|
||||
const hasJsx = isJsxNode(n.right);
|
||||
|
||||
const firstGroupIndex = parts.findIndex(
|
||||
(part) => typeof part !== "string" && part.type === "group"
|
||||
(part) =>
|
||||
typeof part !== "string" && !Array.isArray(part) && part.type === "group"
|
||||
);
|
||||
|
||||
// Separate the leftmost expression, possibly with its leading comments.
|
||||
@@ -278,7 +279,7 @@ function printBinaryishExpressions(
|
||||
if (printed.type === "string") {
|
||||
parts = [printed];
|
||||
} else {
|
||||
parts = printed.parts;
|
||||
parts = getDocParts(printed);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -102,6 +102,7 @@ function printObject(path, options, print) {
|
||||
}, field);
|
||||
});
|
||||
|
||||
/** @type {Doc[]} */
|
||||
let separatorParts = [];
|
||||
const props = propsAndLoc
|
||||
.sort((a, b) => a.loc - b.loc)
|
||||
|
||||
@@ -23,7 +23,7 @@ const {
|
||||
indent,
|
||||
group,
|
||||
},
|
||||
utils: { normalizeDoc },
|
||||
utils: { normalizeDoc, getDocParts },
|
||||
printer: { printDocToString },
|
||||
} = require("../document");
|
||||
const { replaceEndOfLineWith } = require("../common/util");
|
||||
@@ -578,7 +578,7 @@ function printLine(path, value, options) {
|
||||
}
|
||||
|
||||
function printTable(path, options, print) {
|
||||
const hardlineWithoutBreakParent = hardline.parts[0];
|
||||
const hardlineWithoutBreakParent = getDocParts(hardline)[0];
|
||||
const node = path.getValue();
|
||||
|
||||
const columnMaxWidths = [];
|
||||
|
||||
@@ -14,6 +14,7 @@ const {
|
||||
literalline,
|
||||
markAsRoot,
|
||||
},
|
||||
utils: { getDocParts },
|
||||
} = require("../../document");
|
||||
const {
|
||||
getAncestorCount,
|
||||
@@ -55,7 +56,7 @@ function printBlock(path, print, options) {
|
||||
if (index === 0) {
|
||||
contentsParts.push(hardline);
|
||||
}
|
||||
contentsParts.push(fill(join(line, lineWords).parts));
|
||||
contentsParts.push(fill(getDocParts(join(line, lineWords))));
|
||||
if (index !== lineContents.length - 1) {
|
||||
contentsParts.push(
|
||||
lineWords.length === 0 ? hardline : markAsRoot(literalline)
|
||||
|
||||
@@ -14,6 +14,7 @@ const {
|
||||
lineSuffix,
|
||||
literalline,
|
||||
},
|
||||
utils: { getDocParts },
|
||||
} = require("../document");
|
||||
const { replaceEndOfLineWith, isPreviousLineEmpty } = require("../common/util");
|
||||
const { insertPragma, isPragma } = require("./pragma");
|
||||
@@ -444,7 +445,7 @@ function printFlowScalarContent(nodeType, content, options) {
|
||||
return join(
|
||||
hardline,
|
||||
lineContents.map((lineContentWords) =>
|
||||
fill(join(line, lineContentWords).parts)
|
||||
fill(getDocParts(join(line, lineContentWords)))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,9 +27,13 @@ describe("API", () => {
|
||||
});
|
||||
|
||||
const doc = printToDoc(code, options);
|
||||
test("prettier.printToDoc", () => {
|
||||
expect(doc.type).toBe("concat");
|
||||
expect(Array.isArray(doc.parts)).toBe(true);
|
||||
test("prettier.printToDoc", (done) => {
|
||||
// If it's array, it's a `concat`
|
||||
if (!Array.isArray(doc)) {
|
||||
expect(doc.type).toBe("concat");
|
||||
expect(Array.isArray(doc.parts)).toBe(true);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
const formatResultFromDoc = formatDoc(doc, options);
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
"use strict";
|
||||
|
||||
const prettier = require("prettier-local");
|
||||
const {
|
||||
concat,
|
||||
join,
|
||||
hardline,
|
||||
literalline,
|
||||
group,
|
||||
fill,
|
||||
lineSuffix,
|
||||
breakParent,
|
||||
ifBreak,
|
||||
indent,
|
||||
align,
|
||||
} = prettier.doc.builders;
|
||||
|
||||
// TODO: Make these builders to use array if possible in 3.0.0
|
||||
describe("doc builders", () => {
|
||||
test.each([
|
||||
["concat", concat(["1", "2"]), { type: "concat", parts: ["1", "2"] }],
|
||||
[
|
||||
"join",
|
||||
join(concat(["1"]), ["2", concat(["3"])]),
|
||||
{
|
||||
type: "concat",
|
||||
parts: [
|
||||
"2",
|
||||
{ type: "concat", parts: ["1"] },
|
||||
{ type: "concat", parts: ["3"] },
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
"join(array)",
|
||||
join(["1"], ["2", concat(["3"])]),
|
||||
{ type: "concat", parts: ["2", ["1"], { type: "concat", parts: ["3"] }] },
|
||||
],
|
||||
[
|
||||
"hardline",
|
||||
hardline,
|
||||
{ type: "concat", parts: [{ type: "line", hard: true }, breakParent] },
|
||||
],
|
||||
[
|
||||
"literalline",
|
||||
literalline,
|
||||
{
|
||||
type: "concat",
|
||||
parts: [{ type: "line", hard: true, literal: true }, breakParent],
|
||||
},
|
||||
],
|
||||
[
|
||||
"group",
|
||||
group(concat(["1"])),
|
||||
{
|
||||
type: "group",
|
||||
id: undefined,
|
||||
contents: { type: "concat", parts: ["1"] },
|
||||
break: false,
|
||||
expandedStates: undefined,
|
||||
},
|
||||
],
|
||||
[
|
||||
"group (array)",
|
||||
group(["1"]),
|
||||
{
|
||||
type: "group",
|
||||
id: undefined,
|
||||
contents: ["1"],
|
||||
break: false,
|
||||
expandedStates: undefined,
|
||||
},
|
||||
],
|
||||
["fill", fill(["1", "2"]), { type: "fill", parts: ["1", "2"] }],
|
||||
[
|
||||
"line-suffix",
|
||||
lineSuffix(concat(["1"])),
|
||||
{
|
||||
type: "line-suffix",
|
||||
contents: { type: "concat", parts: ["1"] },
|
||||
},
|
||||
],
|
||||
[
|
||||
"line-suffix(array)",
|
||||
lineSuffix(["1"]),
|
||||
{
|
||||
type: "line-suffix",
|
||||
contents: ["1"],
|
||||
},
|
||||
],
|
||||
[
|
||||
"if-break",
|
||||
ifBreak(concat(["1"]), ["2"]),
|
||||
{
|
||||
type: "if-break",
|
||||
breakContents: { type: "concat", parts: ["1"] },
|
||||
flatContents: ["2"],
|
||||
groupId: undefined,
|
||||
},
|
||||
],
|
||||
[
|
||||
"indent",
|
||||
indent(concat(["1"])),
|
||||
{
|
||||
type: "indent",
|
||||
contents: { type: "concat", parts: ["1"] },
|
||||
},
|
||||
],
|
||||
[
|
||||
"indent(array)",
|
||||
indent(["1"]),
|
||||
{
|
||||
type: "indent",
|
||||
contents: ["1"],
|
||||
},
|
||||
],
|
||||
[
|
||||
"align",
|
||||
align(" ", concat(["1"])),
|
||||
{
|
||||
type: "align",
|
||||
contents: { type: "concat", parts: ["1"] },
|
||||
n: " ",
|
||||
},
|
||||
],
|
||||
[
|
||||
"align(array)",
|
||||
align(" ", ["1"]),
|
||||
{
|
||||
type: "align",
|
||||
contents: ["1"],
|
||||
n: " ",
|
||||
},
|
||||
],
|
||||
])("%s", (_, doc, expected) => {
|
||||
expect(doc).toEqual(expected);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user