Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract printClass and printTypeParameters #9713

Merged
merged 7 commits into from Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
143 changes: 143 additions & 0 deletions src/language-js/print/class.js
@@ -0,0 +1,143 @@
"use strict";

const { printComments, printDanglingComments } = require("../../main/comments");
const {
builders: { concat, join, line, hardline, softline, group, indent, ifBreak },
} = require("../../document");
const { hasTrailingComment, hasTrailingLineComment } = require("../utils");
const { getTypeParametersGroupId } = require("./type-parameters");

function printClass(path, options, print) {
const n = path.getValue();
const parts = [];

if (n.abstract) {
parts.push("abstract ");
}

parts.push("class");

// Keep old behaviour of extends in same line
// If there is only on extends and there are not comments
const groupMode =
(n.id && hasTrailingComment(n.id)) ||
(n.superClass &&
n.superClass.comments &&
n.superClass.comments.length !== 0) ||
(n.extends && n.extends.length !== 0) || // DeclareClass
(n.mixins && n.mixins.length !== 0) ||
(n.implements && n.implements.length !== 0);

const partsGroup = [];
const extendsParts = [];

if (n.id) {
partsGroup.push(" ", path.call(print, "id"));
}

partsGroup.push(path.call(print, "typeParameters"));

if (n.superClass) {
const printed = concat([
"extends ",
printSuperClass(path, options, print),
path.call(print, "superTypeParameters"),
]);
const printedWithComments = path.call(
(superClass) => printComments(superClass, () => printed, options),
"superClass"
);
if (groupMode) {
extendsParts.push(line, group(printedWithComments));
} else {
extendsParts.push(" ", printedWithComments);
}
} else {
extendsParts.push(printList(path, options, print, "extends"));
}

extendsParts.push(printList(path, options, print, "mixins"));
extendsParts.push(printList(path, options, print, "implements"));

if (groupMode) {
const printedExtends = concat(extendsParts);
if (shouldIndentOnlyHeritageClauses(n)) {
parts.push(
group(
concat(
partsGroup.concat(ifBreak(indent(printedExtends), printedExtends))
)
)
);
} else {
parts.push(group(indent(concat(partsGroup.concat(printedExtends)))));
}
} else {
parts.push(...partsGroup, ...extendsParts);
}

parts.push(" ", path.call(print, "body"));

return concat(parts);
}

function hasMultipleHeritage(node) {
return (
["superClass", "extends", "mixins", "implements"].filter(
(key) => !!node[key]
).length > 1
);
}

function shouldIndentOnlyHeritageClauses(node) {
return (
node.typeParameters &&
!hasTrailingLineComment(node.typeParameters) &&
!hasMultipleHeritage(node)
);
}

function printList(path, options, print, listName) {
const n = path.getValue();
if (!n[listName] || n[listName].length === 0) {
return "";
}

const printedLeadingComments = printDanglingComments(
path,
options,
/* sameIndent */ true,
({ marker }) => marker === listName
);
return concat([
shouldIndentOnlyHeritageClauses(n)
? ifBreak(" ", line, {
groupId: getTypeParametersGroupId(n.typeParameters),
})
: line,
printedLeadingComments,
printedLeadingComments && hardline,
listName,
group(
indent(
concat([line, join(concat([",", line]), path.map(print, listName))])
)
),
]);
}

function printSuperClass(path, options, print) {
const printed = path.call(print, "superClass");
const parent = path.getParentNode();
if (parent && parent.type === "AssignmentExpression") {
return concat([
ifBreak("("),
indent(concat([softline, printed])),
softline,
ifBreak(")"),
]);
}
return printed;
}

module.exports = { printClass };
100 changes: 100 additions & 0 deletions src/language-js/print/type-parameters.js
@@ -0,0 +1,100 @@
"use strict";

const { printDanglingComments } = require("../../main/comments");
const {
builders: { concat, join, line, hardline, softline, group, indent, ifBreak },
} = require("../../document");
const {
hasDanglingComments,
isTestCall,
isBlockComment,
shouldPrintComma,
} = require("../utils");
const { shouldHugType } = require("./type-annotation");

const typeParametersGroupIds = new WeakMap();
function getTypeParametersGroupId(node) {
if (!typeParametersGroupIds.has(node)) {
typeParametersGroupIds.set(node, Symbol("typeParameters"));
}
return typeParametersGroupIds.get(node);
}

function printTypeParameters(path, options, print, paramsKey) {
const n = path.getValue();

if (!n[paramsKey]) {
return "";
}

// for TypeParameterDeclaration typeParameters is a single node
if (!Array.isArray(n[paramsKey])) {
return path.call(print, paramsKey);
}

const grandparent = path.getNode(2);
const isParameterInTestCall = grandparent != null && isTestCall(grandparent);

const shouldInline =
isParameterInTestCall ||
n[paramsKey].length === 0 ||
(n[paramsKey].length === 1 &&
(shouldHugType(n[paramsKey][0]) ||
(n[paramsKey][0].type === "GenericTypeAnnotation" &&
shouldHugType(n[paramsKey][0].id)) ||
(n[paramsKey][0].type === "TSTypeReference" &&
shouldHugType(n[paramsKey][0].typeName)) ||
n[paramsKey][0].type === "NullableTypeAnnotation"));

if (shouldInline) {
return concat([
"<",
join(", ", path.map(print, paramsKey)),
printDanglingCommentsForInline(path, options),
">",
]);
}

return group(
concat([
"<",
indent(
concat([
softline,
join(concat([",", line]), path.map(print, paramsKey)),
])
),
ifBreak(
options.parser !== "typescript" &&
options.parser !== "babel-ts" &&
shouldPrintComma(options, "all")
? ","
: ""
),
softline,
">",
]),
{ id: getTypeParametersGroupId(n) }
);
}

function printDanglingCommentsForInline(path, options) {
const n = path.getValue();
if (!hasDanglingComments(n)) {
return "";
}
const hasOnlyBlockComments = n.comments.every((comment) =>
isBlockComment(comment)
);
const printed = printDanglingComments(
path,
options,
/* sameIndent */ hasOnlyBlockComments
);
if (hasOnlyBlockComments) {
return printed;
}
return concat([printed, hardline]);
}

module.exports = { printTypeParameters, getTypeParametersGroupId };