Centralize "class like" children related logic (#18789)

This commit is contained in:
fisker Cheung authored and GitHub committed 2026-01-29 20:03:37 +08:00
1 parent 66fba05522
commit e52130244a
3 files changed
+89 -64

No files matched your search

+2 -54
View File
@@ -10,6 +10,7 @@ import { printDanglingComments } from "../../main/comments/print.js";
import hasNewline from "../../utilities/has-newline.js";
import hasNewlineInRange from "../../utilities/has-newline-in-range.js";
import { locEnd, locStart } from "../loc.js";
import { iterateClassMembersPath } from "../utilities/class-members.js";
import {
CommentCheckFlags,
getComments,
@@ -40,7 +41,7 @@ function printClassBody(path, options, print) {
isFlowTypeAnnotation && node.exact ? ["{|", "|}"] : "{}";
let firstMember;
iterateClassMembers(path, ({ node, next, isLast }) => {
iterateClassMembersPath(path, ({ node, next, isLast }) => {
firstMember ??= node;
parts.push(print());
@@ -172,59 +173,6 @@ function isClassBody(path) {
);
}
function iterateClassMembers(path, iteratee) {
const { node } = path;
if (node.type === "ClassBody" || node.type === "TSInterfaceBody") {
path.each(iteratee, "body");
return;
}
if (node.type === "TSTypeLiteral") {
path.each(iteratee, "members");
return;
}
if (node.type === "RecordDeclarationBody") {
path.each(iteratee, "elements");
return;
}
if (node.type === "ObjectTypeAnnotation") {
// Unfortunately, things grouped together in the ast can be
// interleaved in the source code. So we need to reorder them before
// printing them.
const children = [
"properties",
"indexers",
"callProperties",
"internalSlots",
]
.flatMap((field) =>
path.map(
({ node, index }) => ({
node,
loc: locStart(node),
selector: [field, index],
}),
field,
),
)
.sort((a, b) => a.loc - b.loc);
for (const [index, { node, selector }] of children.entries()) {
path.call(
() =>
iteratee({
node,
next: children[index + 1]?.node,
isLast: index === children.length - 1,
}),
...selector,
);
}
}
}
function printClassMemberSemicolon(path, options) {
const { parent } = path;
+1 -10
View File
@@ -14,6 +14,7 @@ import {
} from "../../main/comments/print.js";
import createGroupIdMapper from "../../utilities/create-group-id-mapper.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { isNonEmptyClassBody } from "../utilities/class-members.js";
import { CommentCheckFlags, hasComment } from "../utilities/comments.js";
import { createTypeCheckFunction } from "../utilities/create-type-check-function.js";
import { isMemberExpression } from "../utilities/node-types.js";
@@ -143,16 +144,6 @@ function printClass(path, options, print) {
return parts;
}
function isNonEmptyClassBody(node) {
return node.type === "ObjectTypeAnnotation"
? ["properties", "indexers", "callProperties", "internalSlots"].some(
(property) => isNonEmptyArray(node[property]),
)
: node.type === "RecordDeclarationBody"
? isNonEmptyArray(node.elements)
: isNonEmptyArray(node.body);
}
function hasMultipleHeritage(node) {
let count = node.superClass ? 1 : 0;
for (const listName of ["extends", "mixins", "implements"]) {
@@ -0,0 +1,86 @@
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { locStart } from "../loc.js";
/**
@import AstPath from "../../common/ast-path.js";
@import {Node, NodeMap} from "../types/estree.js";
*/
const flowObjectTypeAnnotationChildrenProperties = [
"properties",
"indexers",
"callProperties",
"internalSlots",
];
function iterateClassMembersPath(path, iteratee) {
const { node } = path;
if (node.type === "ClassBody" || node.type === "TSInterfaceBody") {
path.each(iteratee, "body");
return;
}
if (node.type === "TSTypeLiteral") {
path.each(iteratee, "members");
return;
}
if (node.type === "RecordDeclarationBody") {
path.each(iteratee, "elements");
return;
}
if (node.type === "ObjectTypeAnnotation") {
// Unfortunately, things grouped together in the ast can be
// interleaved in the source code. So we need to reorder them before
// printing them.
const children = flowObjectTypeAnnotationChildrenProperties
.flatMap((field) =>
path.map(
({ node, index }) => ({
node,
loc: locStart(node),
selector: [field, index],
}),
field,
),
)
.sort((a, b) => a.loc - b.loc);
for (const [index, { node, selector }] of children.entries()) {
path.call(
() =>
iteratee({
node,
next: children[index + 1]?.node,
isLast: index === children.length - 1,
}),
...selector,
);
}
}
}
/**
@param {
| NodeMap["ClassBody"]
| NodeMap["TSInterfaceBody"]
| NodeMap["RecordDeclarationBody"]
| NodeMap["ObjectTypeAnnotation"]
} node
@returns {boolean}
*/
function isNonEmptyClassBody(node) {
if (node.type === "ObjectTypeAnnotation") {
return flowObjectTypeAnnotationChildrenProperties.some((property) =>
isNonEmptyArray(node[property]),
);
}
const members =
node.type === "RecordDeclarationBody" ? node.elements : node.body;
return isNonEmptyArray(members);
}
export { isNonEmptyClassBody, iterateClassMembersPath };