Refactor comment printers to accept filter option (#18768)

This commit is contained in:
fisker Cheung authored and GitHub committed 2026-01-28 02:58:09 +08:00
1 parent 187680371e
commit 04d90fd5b5
3 files changed
+120 -73

No files matched your search

+7 -11
View File
@@ -1,6 +1,6 @@
import {
printComments,
printCommentsSeparately,
printLeadingComments,
} from "../../main/comments/print.js";
import {
isSingleHtmlEventHandlerExpressionStatement,
@@ -57,17 +57,13 @@ function printExpressionStatement(path, options, print) {
);
// Print the type cast comment separately and print `;` before it
// eslint-disable-next-line prettier-internal-rules/no-node-comments
const { comments } = node;
// eslint-disable-next-line prettier-internal-rules/no-node-comments
node.comments = [typeCastComment];
const typeCastCommentDoc = printCommentsSeparately(path, options).leading;
// eslint-disable-next-line prettier-internal-rules/no-node-comments
node.comments = comments;
// Make it printed, so `printComments` will ignore it
options[Symbol.for("printedComments")].add(typeCastComment);
const typeCastCommentDoc = printLeadingComments(path, options, {
filter: (comment) => comment === typeCastComment,
});
return printComments(path, [";", typeCastCommentDoc, ...parts], options);
return printComments(path, [";", typeCastCommentDoc, ...parts], options, {
filter: (comment) => comment !== typeCastComment,
});
}
parts.unshift(";");
+6 -1
View File
@@ -1,5 +1,6 @@
import AstPath from "../common/ast-path.js";
import { cursor, inheritLabel } from "../document/index.js";
import isNonEmptyArray from "../utilities/is-non-empty-array.js";
import isObject from "../utilities/is-object.js";
import { attachComments } from "./comments/attach.js";
import { ensureAllCommentsPrinted, printComments } from "./comments/print.js";
@@ -128,7 +129,11 @@ function callPluginPrintFunction(path, options, printPath, args, embeds) {
// We let JSXElement print its comments itself because it adds () around
// UnionTypeAnnotation has to align the child without the comments
if (printer.printComment && !printer.willPrintOwnComments?.(path, options)) {
if (
printer.printComment &&
isNonEmptyArray(node.comments) &&
!printer.willPrintOwnComments?.(path, options)
) {
// printComments will call the plugin print function and check for
// comments to print
doc = printComments(path, doc, options);
+107 -61
View File
@@ -8,15 +8,17 @@ import {
lineSuffix,
} from "../../document/index.js";
import hasNewline from "../../utilities/has-newline.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import isPreviousLineEmpty from "../../utilities/is-previous-line-empty.js";
import { skipSpaces } from "../../utilities/skip.js";
import skipNewline from "../../utilities/skip-newline.js";
/**
* @import AstPath from "../../common/ast-path.js"
* @import {Doc, HardLine, Line} from "../../document/index.js"
*/
@import AstPath from "../../common/ast-path.js"
@import {Doc, HardLine, Line} from "../../document/index.js"
@typedef {{
filter?: (comment) => boolean,
}} CommentPrintOptions
*/
const returnTrue = () => true;
@@ -111,10 +113,9 @@ function printTrailingComment(path, options, previousComment) {
/**
* @param {AstPath} path
* @param {{
* @param {CommentPrintOptions & {
* indent?: boolean,
* marker?: symbol | string,
* filter?: (comment) => boolean,
* }} [danglingCommentsPrintOptions]
* @returns {Doc}
*/
@@ -123,89 +124,133 @@ function printDanglingComments(
options,
danglingCommentsPrintOptions = {},
) {
const { node } = path;
if (!isNonEmptyArray(node?.comments)) {
return "";
}
const {
indent: shouldIndent = false,
marker,
filter = returnTrue,
} = danglingCommentsPrintOptions;
const danglingComments = new Set(
path.node?.comments?.filter(
(comment) =>
!(
comment.leading ||
comment.trailing ||
comment.marker !== marker ||
!filter(comment)
),
),
);
const parts = [];
path.each(({ node: comment }) => {
if (
comment.leading ||
comment.trailing ||
comment.marker !== marker ||
!filter(comment)
) {
return;
}
parts.push(printComment(path, options));
}, "comments");
if (parts.length === 0) {
if (danglingComments.size === 0) {
return "";
}
const parts = path
.map(
({ node: comment }) =>
danglingComments.has(comment) ? printComment(path, options) : "",
"comments",
)
.filter(Boolean);
const doc = join(hardline, parts);
return shouldIndent ? indent([hardline, doc]) : doc;
}
/**
@returns {{leading?: Doc, trailing?: Doc}}
@param {AstPath} path
@param {CommentPrintOptions} [printOptions]
@returns {Doc}
*/
function printCommentsSeparately(path, options) {
const value = path.node;
if (!value) {
return {};
}
const ignored = options[Symbol.for("printedComments")];
const comments = (value.comments || []).filter(
(comment) => !ignored.has(comment),
function printLeadingComments(path, options, printOptions) {
const printed = options[Symbol.for("printedComments")];
const filter = printOptions?.filter ?? returnTrue;
const leadingComments = new Set(
path.node?.comments?.filter(
(comment) => !printed?.has(comment) && comment.leading && filter(comment),
),
);
if (comments.length === 0) {
return { leading: "", trailing: "" };
if (leadingComments.size === 0) {
return "";
}
const leadingParts = [];
const trailingParts = [];
return path
.map(
({ node: comment }) =>
leadingComments.has(comment) ? printLeadingComment(path, options) : "",
"comments",
)
.filter(Boolean);
}
/**
@param {AstPath} path
@param {CommentPrintOptions} [printOptions]
@returns {Doc}
*/
function printTrailingComments(path, options, printOptions) {
const comments = path.node?.comments;
const trailingComments = new Set(
comments?.filter((comment) => comment.trailing),
);
const printed = options[Symbol.for("printedComments")];
const filter = printOptions?.filter ?? returnTrue;
const commentsShouldPrint = new Set(
comments?.filter(
(comment) =>
trailingComments.has(comment) &&
!printed?.has(comment) &&
filter(comment),
),
);
if (commentsShouldPrint.size === 0) {
return "";
}
const docs = [];
let printedTrailingComment;
path.each(() => {
const comment = path.node;
if (ignored?.has(comment)) {
path.each(({ node: comment }) => {
if (!trailingComments.has(comment)) {
return;
}
const { leading, trailing } = comment;
if (leading) {
leadingParts.push(printLeadingComment(path, options));
} else if (trailing) {
printedTrailingComment = printTrailingComment(
path,
options,
printedTrailingComment,
);
trailingParts.push(printedTrailingComment.doc);
printedTrailingComment = printTrailingComment(
path,
options,
printedTrailingComment,
);
if (commentsShouldPrint.has(comment)) {
docs.push(printedTrailingComment.doc);
}
}, "comments");
return { leading: leadingParts, trailing: trailingParts };
return docs;
}
function printComments(path, doc, options) {
const { leading, trailing } = printCommentsSeparately(path, options);
if (!leading && !trailing) {
return doc;
}
return inheritLabel(doc, (doc) => [leading, doc, trailing]);
/**
@param {CommentPrintOptions} [printOptions]
@returns {{leading: Doc, trailing: Doc}}
*/
function printCommentsSeparately(path, options, printOptions) {
return {
leading: printLeadingComments(path, options, printOptions),
trailing: printTrailingComments(path, options, printOptions),
};
}
/**
@param {CommentPrintOptions} [printOptions]
@returns {Doc}
*/
function printComments(path, doc, options, printOptions) {
const leading = printLeadingComments(path, options, printOptions);
const trailing = printTrailingComments(path, options, printOptions);
return leading || trailing
? inheritLabel(doc, (doc) => [leading, doc, trailing])
: doc;
}
function ensureAllCommentsPrinted(options) {
@@ -231,4 +276,5 @@ export {
printComments,
printCommentsSeparately,
printDanglingComments,
printLeadingComments,
};