Improve visual separation between header and body in classes with multiline headers (#10085)
* Add hardline for a class whose extends part is broken refactor Use groupId Remove isPreviousLineEmpty * Avoid leading comments * Rename to heritage * Add heuristic for implements * Fix lint problems * Fix Fix Fix * Extract getGroupId patterns * Adopots solution 2 * Fix * Fix lint problem * Add changelog * Address reviews * Update tests * Rename to createGroupIdMapper * Split files * Add tests for complex extends * Fix changelog
This commit is contained in:
1 parent
af9478009e
commit
c7a3c16f7d
12 files changed
+246
-29
No files matched your search
@@ -0,0 +1,28 @@
|
||||
#### Improve visual separation between header and body in classes with multiline headers (#10085 by @sosukesuzuki)
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```ts
|
||||
// Input
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements loooooooooooooooooooong
|
||||
{
|
||||
property: string;
|
||||
}
|
||||
|
||||
// Prettier stable
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements loooooooooooooooooooong {
|
||||
property: string;
|
||||
}
|
||||
|
||||
// Prettier master
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements loooooooooooooooooooong
|
||||
{
|
||||
property: string;
|
||||
}
|
||||
|
||||
```
|
||||
@@ -628,6 +628,20 @@ function isNonEmptyArray(object) {
|
||||
return Array.isArray(object) && object.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} description
|
||||
* @returns {(node: any) => symbol}
|
||||
*/
|
||||
function createGroupIdMapper(description) {
|
||||
const groupIds = new WeakMap();
|
||||
return function (node) {
|
||||
if (!groupIds.has(node)) {
|
||||
groupIds.set(node, Symbol(description));
|
||||
}
|
||||
return groupIds.get(node);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
inferParserByLanguage,
|
||||
replaceEndOfLineWith,
|
||||
@@ -665,4 +679,5 @@ module.exports = {
|
||||
isFrontMatterNode,
|
||||
getShebang,
|
||||
isNonEmptyArray,
|
||||
createGroupIdMapper,
|
||||
};
|
||||
@@ -6,6 +6,7 @@ const {
|
||||
builders: { hardline, indent },
|
||||
} = require("../../document");
|
||||
const { hasComment, CommentCheckFlags, isNextLineEmpty } = require("../utils");
|
||||
const { printHardlineAfterHeritage } = require("./class");
|
||||
|
||||
const { printBody } = require("./statement");
|
||||
|
||||
@@ -19,6 +20,11 @@ function printBlock(path, options, print) {
|
||||
parts.push("static ");
|
||||
}
|
||||
|
||||
if (node.type === "ClassBody" && isNonEmptyArray(node.body)) {
|
||||
const parent = path.getParentNode();
|
||||
parts.push(printHardlineAfterHeritage(parent));
|
||||
}
|
||||
|
||||
parts.push("{");
|
||||
const printed = printBlockBody(path, options, print);
|
||||
if (printed) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
const { isNonEmptyArray } = require("../../common/util");
|
||||
const { isNonEmptyArray, createGroupIdMapper } = require("../../common/util");
|
||||
const { printComments, printDanglingComments } = require("../../main/comments");
|
||||
const {
|
||||
builders: { join, line, hardline, softline, group, indent, ifBreak },
|
||||
@@ -72,15 +72,16 @@ function printClass(path, options, print) {
|
||||
|
||||
if (groupMode) {
|
||||
const printedExtends = extendsParts;
|
||||
let printedPartsGroup;
|
||||
if (shouldIndentOnlyHeritageClauses(n)) {
|
||||
parts.push(
|
||||
group(
|
||||
partsGroup.concat(ifBreak(indent(printedExtends), printedExtends))
|
||||
)
|
||||
);
|
||||
printedPartsGroup = [
|
||||
...partsGroup,
|
||||
ifBreak(indent(printedExtends), printedExtends),
|
||||
];
|
||||
} else {
|
||||
parts.push(group(indent(partsGroup.concat(printedExtends))));
|
||||
printedPartsGroup = indent([...partsGroup, printedExtends]);
|
||||
}
|
||||
parts.push(group(printedPartsGroup, { id: getHeritageGroupId(n) }));
|
||||
} else {
|
||||
parts.push(...partsGroup, ...extendsParts);
|
||||
}
|
||||
@@ -90,6 +91,12 @@ function printClass(path, options, print) {
|
||||
return parts;
|
||||
}
|
||||
|
||||
const getHeritageGroupId = createGroupIdMapper("heritageGroup");
|
||||
|
||||
function printHardlineAfterHeritage(node) {
|
||||
return ifBreak(hardline, "", { groupId: getHeritageGroupId(node) });
|
||||
}
|
||||
|
||||
function hasMultipleHeritage(node) {
|
||||
return (
|
||||
["superClass", "extends", "mixins", "implements"].filter(
|
||||
@@ -222,4 +229,5 @@ module.exports = {
|
||||
printClass,
|
||||
printClassMethod,
|
||||
printClassProperty,
|
||||
printHardlineAfterHeritage,
|
||||
};
|
||||
@@ -4,7 +4,12 @@ const { printDanglingComments } = require("../../main/comments");
|
||||
const {
|
||||
builders: { line, softline, group, indent, ifBreak, hardline },
|
||||
} = require("../../document");
|
||||
const { getLast, hasNewlineInRange, hasNewline } = require("../../common/util");
|
||||
const {
|
||||
getLast,
|
||||
hasNewlineInRange,
|
||||
hasNewline,
|
||||
isNonEmptyArray,
|
||||
} = require("../../common/util");
|
||||
const {
|
||||
shouldPrintComma,
|
||||
hasComment,
|
||||
@@ -17,6 +22,7 @@ const { locStart, locEnd } = require("../loc");
|
||||
const { printOptionalToken, printTypeAnnotation } = require("./misc");
|
||||
const { shouldHugFunctionParameters } = require("./function-parameters");
|
||||
const { shouldHugType } = require("./type-annotation");
|
||||
const { printHardlineAfterHeritage } = require("./class");
|
||||
|
||||
/** @typedef {import("../../document").Doc} Doc */
|
||||
|
||||
@@ -175,6 +181,9 @@ function printObject(path, options, print) {
|
||||
]);
|
||||
} else {
|
||||
content = [
|
||||
isFlowInterfaceLikeBody && isNonEmptyArray(n.properties)
|
||||
? printHardlineAfterHeritage(parent)
|
||||
: "",
|
||||
leftBrace,
|
||||
indent([options.bracketSpacing ? line : softline, ...props]),
|
||||
ifBreak(
|
||||
|
||||
@@ -12,15 +12,10 @@ const {
|
||||
shouldPrintComma,
|
||||
getFunctionParameters,
|
||||
} = require("../utils");
|
||||
const { createGroupIdMapper } = require("../../common/util");
|
||||
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);
|
||||
}
|
||||
const getTypeParametersGroupId = createGroupIdMapper("typeParameters");
|
||||
|
||||
function printTypeParameters(path, options, print, paramsKey) {
|
||||
const n = path.getValue();
|
||||
|
||||
@@ -146,7 +146,8 @@ class c extends d {
|
||||
}
|
||||
|
||||
class C2 // comment
|
||||
extends Base {
|
||||
extends Base
|
||||
{
|
||||
foo() {}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`complex.js format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["babel", "flow", "typescript"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
class loooooooooooooooooooong1 extends foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo()))))))) {}
|
||||
|
||||
class loooooooooooooooooooong2 extends function (make, model, year, owner) {
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
this.year = year;
|
||||
this.owner = owner;
|
||||
} {}
|
||||
|
||||
class loooooooooooooooooooong3 extends class {
|
||||
cconstructor(make, model, year, owner) {
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
this.year = year;
|
||||
this.owner = owner;
|
||||
}
|
||||
} {}
|
||||
|
||||
=====================================output=====================================
|
||||
class loooooooooooooooooooong1 extends foooooooo(
|
||||
foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo()))))))
|
||||
) {}
|
||||
|
||||
class loooooooooooooooooooong2 extends function (make, model, year, owner) {
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
this.year = year;
|
||||
this.owner = owner;
|
||||
} {}
|
||||
|
||||
class loooooooooooooooooooong3 extends class {
|
||||
cconstructor(make, model, year, owner) {
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
this.year = year;
|
||||
this.owner = owner;
|
||||
}
|
||||
} {}
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`extends.js format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["babel", "flow", "typescript"]
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
class loooooooooooooooooooong1 extends foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo(foooooooo()))))))) {}
|
||||
|
||||
class loooooooooooooooooooong2 extends function (make, model, year, owner) {
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
this.year = year;
|
||||
this.owner = owner;
|
||||
} {}
|
||||
|
||||
class loooooooooooooooooooong3 extends class {
|
||||
cconstructor(make, model, year, owner) {
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
this.year = year;
|
||||
this.owner = owner;
|
||||
}
|
||||
} {}
|
||||
@@ -83,7 +83,8 @@ b // comment-b2
|
||||
=====================================output=====================================
|
||||
class a1
|
||||
extends b // comment
|
||||
implements z {
|
||||
implements z
|
||||
{
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -95,7 +96,8 @@ class a2 extends b implements z {
|
||||
class a3
|
||||
extends b
|
||||
// comment
|
||||
implements z, y {
|
||||
implements z, y
|
||||
{
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -103,7 +105,8 @@ class a4
|
||||
extends b
|
||||
implements
|
||||
z, // comment
|
||||
y {
|
||||
y
|
||||
{
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -111,7 +114,8 @@ class a5
|
||||
extends b
|
||||
implements
|
||||
z, // comment-z
|
||||
y {
|
||||
y
|
||||
{
|
||||
// comment-y
|
||||
constructor() {}
|
||||
}
|
||||
@@ -122,7 +126,8 @@ class a6
|
||||
implements
|
||||
z, // comment-z2
|
||||
// comment-y1
|
||||
y {
|
||||
y
|
||||
{
|
||||
// comment-y2
|
||||
constructor() {}
|
||||
}
|
||||
@@ -133,7 +138,8 @@ class a7
|
||||
implements
|
||||
z, // comment-z2
|
||||
// comment-y1
|
||||
y {
|
||||
y
|
||||
{
|
||||
// comment-y2
|
||||
// comment-y3
|
||||
//comment-body
|
||||
@@ -146,7 +152,8 @@ class a8
|
||||
implements
|
||||
z, // comment-z2
|
||||
// comment-y1
|
||||
y {
|
||||
y
|
||||
{
|
||||
// comment-y2
|
||||
constructor() {}
|
||||
}
|
||||
@@ -159,7 +166,8 @@ class a9
|
||||
implements
|
||||
z, // comment-z2
|
||||
// comment-y1
|
||||
y {
|
||||
y
|
||||
{
|
||||
// comment-y2
|
||||
constructor() {}
|
||||
}
|
||||
@@ -188,7 +196,8 @@ extends B<T> // 3
|
||||
=====================================output=====================================
|
||||
declare class a // 1
|
||||
// extends b // 2
|
||||
implements z, x {
|
||||
implements z, x
|
||||
{
|
||||
// 3
|
||||
doo: boolean;
|
||||
}
|
||||
@@ -233,13 +242,15 @@ class G1<T> implements IPoly<T> {
|
||||
}
|
||||
|
||||
class G2<T> // g2
|
||||
implements IPoly<T> {
|
||||
implements IPoly<T>
|
||||
{
|
||||
x: T;
|
||||
}
|
||||
|
||||
class G3<T> // g3
|
||||
extends U
|
||||
implements IPoly<T> {
|
||||
implements IPoly<T>
|
||||
{
|
||||
x: T;
|
||||
}
|
||||
|
||||
@@ -247,7 +258,8 @@ class G4<
|
||||
T // g4
|
||||
>
|
||||
extends U
|
||||
implements IPoly<T> {
|
||||
implements IPoly<T>
|
||||
{
|
||||
x: T;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ export class VisTimelineComponent2
|
||||
=====================================output=====================================
|
||||
class MyContractSelectionWidget
|
||||
extends React.Component<void, MyContractSelectionWidgetPropsType, void>
|
||||
implements SomethingLarge {
|
||||
implements SomethingLarge
|
||||
{
|
||||
method() {}
|
||||
}
|
||||
|
||||
@@ -89,3 +90,63 @@ export class VisTimelineComponent2
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
exports[`break-heritage.ts format 1`] = `
|
||||
====================================options=====================================
|
||||
parsers: ["typescript", "babel", "flow"]
|
||||
printWidth: 80
|
||||
| printWidth
|
||||
=====================================input======================================
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong {
|
||||
// leading comment
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong {
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong {
|
||||
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong, loooooooooooooooooooong, loooooooooooooooooooong {
|
||||
property: string;
|
||||
}
|
||||
|
||||
=====================================output=====================================
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements loooooooooooooooooooong
|
||||
{
|
||||
// leading comment
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements loooooooooooooooooooong
|
||||
{
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements loooooooooooooooooooong
|
||||
{
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong
|
||||
extends looooooooooooooooooong
|
||||
implements
|
||||
loooooooooooooooooooong,
|
||||
loooooooooooooooooooong,
|
||||
loooooooooooooooooooong
|
||||
{
|
||||
property: string;
|
||||
}
|
||||
|
||||
================================================================================
|
||||
`;
|
||||
@@ -0,0 +1,17 @@
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong {
|
||||
// leading comment
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong {
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong {
|
||||
|
||||
property: string;
|
||||
}
|
||||
|
||||
class loooooooooooooooooooong extends looooooooooooooooooong implements loooooooooooooooooooong, loooooooooooooooooooong, loooooooooooooooooooong {
|
||||
property: string;
|
||||
}
|
||||
Reference in new issue
Block a user