prettierx
Version:
prettierX - a less opinionated fork of the Prettier code formatter
195 lines (167 loc) • 5.55 kB
JavaScript
"use strict";
const { printDanglingComments } = require("../../main/comments");
const {
builders: { line, softline, hardline, group, indent, ifBreak, fill },
} = require("../../document");
const { getLast, hasNewline } = require("../../common/util");
const {
shouldPrintComma,
hasComment,
CommentCheckFlags,
isNextLineEmpty,
isNumericLiteral,
isSignedNumericLiteral,
} = require("../utils");
const { locStart } = require("../loc");
const { printOptionalToken, printTypeAnnotation } = require("./misc");
/** @typedef {import("../../document").Doc} Doc */
function printArray(path, options, print) {
const node = path.getValue();
/** @type{Doc[]} */
const parts = [];
const openBracket = node.type === "TupleExpression" ? "#[" : "[";
const closeBracket = "]";
if (node.elements.length === 0) {
if (!hasComment(node, CommentCheckFlags.Dangling)) {
parts.push(openBracket, closeBracket);
} else {
parts.push(
group([
openBracket,
printDanglingComments(path, options),
softline,
closeBracket,
])
);
}
} else {
const lastElem = getLast(node.elements);
const canHaveTrailingComma = !(lastElem && lastElem.type === "RestElement");
// JavaScript allows you to have empty elements in an array which
// changes its length based on the number of commas. The algorithm
// is that if the last argument is null, we need to force insert
// a comma to ensure JavaScript recognizes it.
// [,].length === 1
// [1,].length === 1
// [1,,].length === 2
//
// Note that getLast returns null if the array is empty, but
// we already check for an empty array just above so we are safe
const needsForcedTrailingComma = lastElem === null;
const groupId = Symbol("array");
const shouldBreak =
!options.__inJestEach &&
node.elements.length > 1 &&
node.elements.every((element, i, elements) => {
const elementType = element && element.type;
if (
elementType !== "ArrayExpression" &&
elementType !== "ObjectExpression"
) {
return false;
}
const nextElement = elements[i + 1];
if (nextElement && elementType !== nextElement.type) {
return false;
}
const itemsKey =
elementType === "ArrayExpression" ? "elements" : "properties";
return element[itemsKey] && element[itemsKey].length > 1;
});
const shouldUseConciseFormatting = isConciselyPrintedArray(node, options);
const trailingComma = !canHaveTrailingComma
? ""
: needsForcedTrailingComma
? ","
: !shouldPrintComma(options)
? ""
: shouldUseConciseFormatting
? ifBreak(",", "", { groupId })
: ifBreak(",");
// [prettierx] --array-bracket-spacing option support (...)
parts.push(
group(
// [prettierx] --array-bracket-spacing option support (...)
[
openBracket,
// [prettierx] --array-bracket-spacing option support (...)
indent([
// [prettierx] --array-bracket-spacing option support (...)
options.arrayBracketSpacing ? line : softline,
shouldUseConciseFormatting
? printArrayItemsConcisely(path, options, print, trailingComma)
: [
printArrayItems(path, options, "elements", print),
trailingComma,
],
printDanglingComments(path, options, /* sameIndent */ true),
]),
// [prettierx] --array-bracket-spacing option support (...)
options.arrayBracketSpacing ? line : softline,
closeBracket,
],
{ shouldBreak, id: groupId }
)
);
}
parts.push(
printOptionalToken(path),
printTypeAnnotation(path, options, print)
);
return parts;
}
function isConciselyPrintedArray(node, options) {
return (
node.elements.length > 1 &&
node.elements.every(
(element) =>
element &&
(isNumericLiteral(element) ||
(isSignedNumericLiteral(element) && !hasComment(element.argument))) &&
!hasComment(
element,
CommentCheckFlags.Trailing | CommentCheckFlags.Line,
(comment) =>
!hasNewline(options.originalText, locStart(comment), {
backwards: true,
})
)
)
);
}
function printArrayItems(path, options, printPath, print) {
const printedElements = [];
let separatorParts = [];
path.each((childPath) => {
printedElements.push(separatorParts, group(print()));
separatorParts = [",", line];
if (
childPath.getValue() &&
isNextLineEmpty(childPath.getValue(), options)
) {
separatorParts.push(softline);
}
}, printPath);
return printedElements;
}
function printArrayItemsConcisely(path, options, print, trailingComma) {
const parts = [];
path.each((childPath, i, elements) => {
const isLast = i === elements.length - 1;
parts.push([print(), isLast ? trailingComma : ","]);
if (!isLast) {
parts.push(
isNextLineEmpty(childPath.getValue(), options)
? [hardline, hardline]
: hasComment(
elements[i + 1],
CommentCheckFlags.Leading | CommentCheckFlags.Line
)
? hardline
: line
);
}
}, "elements");
return fill(parts);
}
module.exports = { printArray, printArrayItems, isConciselyPrintedArray };