Print decorators of ClassExpression on it's own (#18788)

This commit is contained in:
fisker Cheung authored and GitHub committed 2026-01-29 20:27:28 +08:00
1 parent 92d288e3e7
commit 6966c7e488
10 files changed
+234 -95

No files matched your search

+17 -1
View File
@@ -14,13 +14,14 @@ 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 needsParentheses from "../parentheses/needs-parentheses.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";
import { stripChainElementWrappers } from "../utilities/strip-chain-element-wrappers.js";
import { printAssignment } from "./assignment.js";
import { printClassMemberDecorators } from "./decorators.js";
import { printClassMemberDecorators, printDecorators } from "./decorators.js";
import { printMethod } from "./function.js";
import { printKey } from "./key.js";
import {
@@ -56,6 +57,21 @@ const isInterface = createTypeCheckFunction([
- `TSInterfaceDeclaration`(TypeScript)
*/
function printClass(path, options, print) {
const doc = printClassWithoutDecorators(path, options, print);
const { node } = path;
if (node.type === "ClassExpression" && isNonEmptyArray(node.decorators)) {
const decoratorsDoc = printDecorators(path, options, print);
const needsParens = needsParentheses(path, options);
return needsParens
? [indent([softline, decoratorsDoc, doc]), softline]
: [decoratorsDoc, doc];
}
return doc;
}
function printClassWithoutDecorators(path, options, print) {
const { node } = path;
const isPrintingInterface = isInterface(node);
const isPrintingRecord = node.type === "RecordDeclaration";
+6
View File
@@ -1,3 +1,5 @@
import { indent, softline } from "../../document/index.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import { locEnd, locStart } from "../loc.js";
import { shouldExpressionStatementPrintLeadingSemicolon } from "../semicolon/semicolon.js";
@@ -23,6 +25,10 @@ function printIgnored(path, options /* , print*/) {
text = `;${text}`;
}
if (node.type === "ClassExpression" && isNonEmptyArray(node.decorators)) {
return [indent([softline, text]), softline];
}
return text;
}
+7 -17
View File
@@ -1,10 +1,4 @@
import {
group,
indent,
inheritLabel,
line,
softline,
} from "../../document/index.js";
import { group, indent, inheritLabel, softline } from "../../document/index.js";
import { printComments } from "../../main/comments/print.js";
import isNonEmptyArray from "../../utilities/is-non-empty-array.js";
import needsParentheses from "../parentheses/needs-parentheses.js";
@@ -83,13 +77,11 @@ function print(path, options, print, args) {
doc = printCommentsForFunction(path, options, doc);
const hasDecorators = isNonEmptyArray(node.decorators);
const decoratorsDoc = printDecorators(path, options, print);
const isClassExpression = node.type === "ClassExpression";
// Nodes (except `ClassExpression`) with decorators can't have parentheses and don't need leading semicolons
if (hasDecorators && !isClassExpression) {
return inheritLabel(doc, (doc) => group([decoratorsDoc, doc]));
}
const decoratorsDoc =
// `ClassExpression` prints own decorators
node.type !== "ClassExpression" && isNonEmptyArray(node.decorators)
? printDecorators(path, options, print)
: "";
const needsParens = needsParentheses(path, options);
@@ -99,9 +91,7 @@ function print(path, options, print, args) {
return inheritLabel(doc, (doc) => [
needsParens ? "(" : "",
needsParens && isClassExpression && hasDecorators
? [indent([line, decoratorsDoc, doc]), line]
: [decoratorsDoc, doc],
decoratorsDoc ? group([decoratorsDoc, doc]) : doc,
needsParens ? ")" : "",
]);
}
@@ -5,6 +5,11 @@ import { FORMAT_TEST_DIRECTORY } from "./constants.js";
const unstableTests = new Map(
[
["js/identifier/parentheses/let.js", (options) => options.semi === false],
[
"js/ignore/semi/class-expression-decorator.js",
(options) => options.semi === false,
],
["js/ignore/semi/head-ignored.js", (options) => options.semi === false],
"js/comments/return-statement.js",
"js/comments/tagged-template-literal.js",
"js/for/9812-unstable.js",
@@ -1,76 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`class-expression-decorator.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
| printWidth
=====================================input======================================
(
// prettier-ignore
@decorator
class {}
);
=====================================output=====================================
// prettier-ignore
(
@decorator
class {}
);
================================================================================
`;
exports[`class-expression-decorator.js format[acorn] 1`] = `
"Unexpected character '@' (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: Unexpected character '@' (3:2)"
`;
exports[`class-expression-decorator.js format[espree] 1`] = `
"Unexpected character '@' (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: Unexpected character '@'"
`;
exports[`class-expression-decorator.js format[flow] 1`] = `
"Unexpected token \`@\` (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |"
`;
exports[`class-expression-decorator.js format[hermes] 1`] = `
"unrecognized character '@' (3:2)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: unrecognized character '@' (3:2)
@decorator
^"
`;
exports[`decorator.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
+3 -4
View File
@@ -1,8 +1,7 @@
runFormatTest(import.meta, ["babel", "flow", "typescript"], {
errors: {
acorn: ["decorator.js", "class-expression-decorator.js"],
espree: ["decorator.js", "class-expression-decorator.js"],
flow: ["class-expression-decorator.js"],
hermes: ["decorator.js", "class-expression-decorator.js"],
acorn: ["decorator.js"],
espree: ["decorator.js"],
hermes: ["decorator.js"],
},
});
@@ -37,6 +37,149 @@ foo;
================================================================================
`;
exports[`class-expression-decorator.js - {"semi":false} format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
semi: false
| printWidth
=====================================input======================================
(
// prettier-ignore
@decorator
class {}
);
=====================================output=====================================
;// prettier-ignore
(
@decorator
class {}
)
================================================================================
`;
exports[`class-expression-decorator.js - {"semi":false} format[acorn] 1`] = `
"Unexpected character '@' (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: Unexpected character '@' (3:2)"
`;
exports[`class-expression-decorator.js - {"semi":false} format[espree] 1`] = `
"Unexpected character '@' (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: Unexpected character '@'"
`;
exports[`class-expression-decorator.js - {"semi":false} format[flow] 1`] = `
"Unexpected token \`@\` (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |"
`;
exports[`class-expression-decorator.js - {"semi":false} format[hermes] 1`] = `
"unrecognized character '@' (3:2)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: unrecognized character '@' (3:2)
@decorator
^"
`;
exports[`class-expression-decorator.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
| printWidth
=====================================input======================================
(
// prettier-ignore
@decorator
class {}
);
=====================================output=====================================
// prettier-ignore
(
@decorator
class {}
);
================================================================================
`;
exports[`class-expression-decorator.js format[acorn] 1`] = `
"Unexpected character '@' (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: Unexpected character '@' (3:2)"
`;
exports[`class-expression-decorator.js format[espree] 1`] = `
"Unexpected character '@' (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: Unexpected character '@'"
`;
exports[`class-expression-decorator.js format[flow] 1`] = `
"Unexpected token \`@\` (3:3)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |"
`;
exports[`class-expression-decorator.js format[hermes] 1`] = `
"unrecognized character '@' (3:2)
1 | (
2 | // prettier-ignore
> 3 | @decorator
| ^
4 | class {}
5 | );
6 |
Cause: unrecognized character '@' (3:2)
@decorator
^"
`;
exports[`directive.js - {"semi":false} format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
@@ -97,3 +240,40 @@ function foo() {
================================================================================
`;
exports[`head-ignored.js - {"semi":false} format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
semi: false
| printWidth
=====================================input======================================
(
// prettier-ignore
[]
).forEach()
=====================================output=====================================
;// prettier-ignore
[].forEach()
================================================================================
`;
exports[`head-ignored.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
| printWidth
=====================================input======================================
(
// prettier-ignore
[]
).forEach()
=====================================output=====================================
// prettier-ignore
[].forEach();
================================================================================
`;
+12 -2
View File
@@ -1,2 +1,12 @@
runFormatTest(import.meta, ["babel", "flow", "typescript"]);
runFormatTest(import.meta, ["babel", "flow", "typescript"], { semi: false });
const errors = {
acorn: ["class-expression-decorator.js"],
espree: ["class-expression-decorator.js"],
flow: ["class-expression-decorator.js"],
hermes: ["class-expression-decorator.js"],
};
runFormatTest(import.meta, ["babel", "flow", "typescript"], { errors });
runFormatTest(import.meta, ["babel", "flow", "typescript"], {
semi: false,
errors,
});
@@ -0,0 +1,4 @@
(
// prettier-ignore
[]
).forEach()