200 lines
7.4 KiB
JavaScript
200 lines
7.4 KiB
JavaScript
import { util } from "prettier";
|
|
import parser from "./parser.js";
|
|
import { isEmptyStatement, isNonTerminal, isTerminal } from "./printers/helpers.js";
|
|
const formatterOffOnRangesByCst = new WeakMap();
|
|
export function determineFormatterOffOnRanges(cst) {
|
|
const { comments } = cst;
|
|
if (!comments) {
|
|
return;
|
|
}
|
|
const ranges = comments
|
|
.filter(({ image }) => /^(\/\/\s*@formatter:(off|on)\s*|\/\*\s*@formatter:(off|on)\s*\*\/)$/.test(image))
|
|
.reduce((ranges, { image, startOffset }) => {
|
|
const previous = ranges.at(-1);
|
|
if (image.endsWith("off")) {
|
|
if ((previous === null || previous === void 0 ? void 0 : previous.on) !== Infinity) {
|
|
ranges.push({ off: startOffset, on: Infinity });
|
|
}
|
|
}
|
|
else if ((previous === null || previous === void 0 ? void 0 : previous.on) === Infinity) {
|
|
previous.on = startOffset;
|
|
}
|
|
return ranges;
|
|
}, new Array());
|
|
formatterOffOnRangesByCst.set(cst, ranges);
|
|
}
|
|
export function isFullyBetweenFormatterOffOn(path) {
|
|
var _a;
|
|
const { node, root } = path;
|
|
const start = parser.locStart(node);
|
|
const end = parser.locEnd(node);
|
|
return (((_a = formatterOffOnRangesByCst
|
|
.get(root)) === null || _a === void 0 ? void 0 : _a.some(range => range.off < start && end < range.on)) === true);
|
|
}
|
|
export function canAttachComment(node) {
|
|
var _a, _b, _c;
|
|
if (isTerminal(node)) {
|
|
const { name, CATEGORIES } = node.tokenType;
|
|
return (name === "Identifier" ||
|
|
(CATEGORIES === null || CATEGORIES === void 0 ? void 0 : CATEGORIES.find(({ name }) => name === "BinaryOperator")) !== undefined);
|
|
}
|
|
const { children, name } = node;
|
|
switch (name) {
|
|
case "argumentList":
|
|
case "blockStatements":
|
|
case "emptyStatement":
|
|
case "enumBodyDeclarations":
|
|
return false;
|
|
case "annotationInterfaceMemberDeclaration":
|
|
case "classMemberDeclaration":
|
|
case "interfaceMemberDeclaration":
|
|
case "methodBody":
|
|
return !children.Semicolon;
|
|
case "blockStatement":
|
|
return !children.statement || !isEmptyStatement(children.statement[0]);
|
|
case "classBodyDeclaration":
|
|
return !((_a = children.classMemberDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.Semicolon);
|
|
case "recordBodyDeclaration":
|
|
return !((_c = (_b = children.classBodyDeclaration) === null || _b === void 0 ? void 0 : _b[0].children.classMemberDeclaration) === null || _c === void 0 ? void 0 : _c[0].children.Semicolon);
|
|
case "statement":
|
|
return !isEmptyStatement(node);
|
|
case "statementWithoutTrailingSubstatement":
|
|
return !children.emptyStatement;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
export function handleLineComment(commentNode, _, options) {
|
|
return [
|
|
handleBinaryExpressionComments,
|
|
handleFqnOrRefTypeComments,
|
|
handleIfStatementComments,
|
|
handleJumpStatementComments,
|
|
handleLabeledStatementComments,
|
|
handleNameComments
|
|
].some(fn => fn(commentNode, options));
|
|
}
|
|
export function handleRemainingComment(commentNode) {
|
|
return [
|
|
handleFqnOrRefTypeComments,
|
|
handleMethodDeclaratorComments,
|
|
handleNameComments,
|
|
handleJumpStatementComments
|
|
].some(fn => fn(commentNode));
|
|
}
|
|
function handleBinaryExpressionComments(commentNode, options) {
|
|
const { enclosingNode, precedingNode, followingNode } = commentNode;
|
|
if (enclosingNode &&
|
|
isNonTerminal(enclosingNode) &&
|
|
enclosingNode.name === "binaryExpression") {
|
|
if (isBinaryOperator(followingNode)) {
|
|
if (options.experimentalOperatorPosition === "start") {
|
|
util.addLeadingComment(followingNode, commentNode);
|
|
}
|
|
else {
|
|
util.addTrailingComment(followingNode, commentNode);
|
|
}
|
|
return true;
|
|
}
|
|
else if (options.experimentalOperatorPosition === "start" &&
|
|
isBinaryOperator(precedingNode)) {
|
|
util.addLeadingComment(precedingNode, commentNode);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function handleFqnOrRefTypeComments(commentNode) {
|
|
const { enclosingNode, followingNode } = commentNode;
|
|
if (enclosingNode &&
|
|
isNonTerminal(enclosingNode) &&
|
|
enclosingNode.name === "fqnOrRefType" &&
|
|
followingNode) {
|
|
util.addLeadingComment(followingNode, commentNode);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function handleIfStatementComments(commentNode) {
|
|
const { enclosingNode, precedingNode } = commentNode;
|
|
if (enclosingNode &&
|
|
isNonTerminal(enclosingNode) &&
|
|
enclosingNode.name === "ifStatement" &&
|
|
precedingNode &&
|
|
isNonTerminal(precedingNode) &&
|
|
precedingNode.name === "statement") {
|
|
util.addDanglingComment(enclosingNode, commentNode, undefined);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function handleJumpStatementComments(commentNode) {
|
|
const { enclosingNode, precedingNode, followingNode } = commentNode;
|
|
if (enclosingNode &&
|
|
!precedingNode &&
|
|
!followingNode &&
|
|
isNonTerminal(enclosingNode) &&
|
|
["breakStatement", "continueStatement", "returnStatement"].includes(enclosingNode.name)) {
|
|
util.addTrailingComment(enclosingNode, commentNode);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function handleLabeledStatementComments(commentNode) {
|
|
const { enclosingNode, precedingNode } = commentNode;
|
|
if (enclosingNode &&
|
|
precedingNode &&
|
|
isNonTerminal(enclosingNode) &&
|
|
enclosingNode.name === "labeledStatement" &&
|
|
isTerminal(precedingNode) &&
|
|
precedingNode.tokenType.name === "Identifier") {
|
|
util.addLeadingComment(precedingNode, commentNode);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function handleMethodDeclaratorComments(commentNode) {
|
|
const { enclosingNode } = commentNode;
|
|
if (enclosingNode &&
|
|
isNonTerminal(enclosingNode) &&
|
|
enclosingNode.name === "methodDeclarator" &&
|
|
!enclosingNode.children.receiverParameter &&
|
|
!enclosingNode.children.formalParameterList &&
|
|
enclosingNode.children.LBrace[0].startOffset < commentNode.startOffset &&
|
|
commentNode.startOffset < enclosingNode.children.RBrace[0].startOffset) {
|
|
util.addDanglingComment(enclosingNode, commentNode, undefined);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function handleNameComments(commentNode) {
|
|
const { enclosingNode, precedingNode } = commentNode;
|
|
if (enclosingNode &&
|
|
precedingNode &&
|
|
isNonTerminal(enclosingNode) &&
|
|
isTerminal(precedingNode) &&
|
|
precedingNode.tokenType.name === "Identifier" &&
|
|
[
|
|
"ambiguousName",
|
|
"classOrInterfaceTypeToInstantiate",
|
|
"expressionName",
|
|
"moduleDeclaration",
|
|
"moduleName",
|
|
"packageDeclaration",
|
|
"packageName",
|
|
"packageOrTypeName",
|
|
"typeName"
|
|
].includes(enclosingNode.name)) {
|
|
util.addTrailingComment(precedingNode, commentNode);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function isBinaryOperator(node) {
|
|
var _a;
|
|
return (node !== undefined &&
|
|
(isNonTerminal(node)
|
|
? node.name === "shiftOperator"
|
|
: (_a = node.tokenType.CATEGORIES) === null || _a === void 0 ? void 0 : _a.some(({ name }) => name === "BinaryOperator")));
|
|
}
|