Skip to content

Commit cb8004f

Browse files
authored
Fix formatting error on optional call expression and member chain (#15920)
1 parent 0bfcb2d commit cb8004f

File tree

4 files changed

+74
-13
lines changed

4 files changed

+74
-13
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#### Fix formatting error on optional call expression and member chain (#15920 by @sosukesuzuki)
2+
3+
<!-- prettier-ignore -->
4+
```jsx
5+
// Input
6+
a(() => {}, c?.d());
7+
8+
// Prettier stable
9+
TypeError: Cannot read properties of undefined (reading 'type')
10+
11+
// Prettier main
12+
a(() => {}, c?.d());
13+
```

src/language-js/utils/index.js

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -405,16 +405,6 @@ function isTestCall(node, parent) {
405405
/** @return {(node: Node) => boolean} */
406406
const skipChainExpression = (fn) => (node) => {
407407
if (node?.type === "ChainExpression") {
408-
// @ts-expect-error
409-
if (!node.object) {
410-
// @ts-expect-error
411-
node.object = node.expression.object;
412-
}
413-
// @ts-expect-error
414-
if (!node.property) {
415-
// @ts-expect-error
416-
node.property = node.expression.property;
417-
}
418408
node = node.expression;
419409
}
420410

@@ -429,6 +419,22 @@ const isMemberExpression = skipChainExpression(
429419
createTypeCheckFunction(["MemberExpression", "OptionalMemberExpression"]),
430420
);
431421

422+
/**
423+
* Retrieves a property from a node, considering any ChainExpression.
424+
* If the node is a ChainExpression, the property is obtained from its expression.
425+
* Otherwise, the property is obtained directly from the node.
426+
*
427+
* @param {Node} node - The AST node to be processed.
428+
* @param {string} property - The property name to retrieve.
429+
* @returns The property value from the node or its expression.
430+
*/
431+
function getChainProp(node, property) {
432+
if (node.type === "ChainExpression") {
433+
return node.expression[property];
434+
}
435+
return node[property];
436+
}
437+
432438
/**
433439
*
434440
* @param {any} node
@@ -769,7 +775,7 @@ function isSimpleCallArgument(node, depth = 2) {
769775
if (isCallLikeExpression(node)) {
770776
if (
771777
node.type === "ImportExpression" ||
772-
isSimpleCallArgument(node.callee, depth)
778+
isSimpleCallArgument(getChainProp(node, "callee"), depth)
773779
) {
774780
const args = getCallArguments(node);
775781
return args.length <= depth && args.every(isChildSimple);
@@ -779,8 +785,8 @@ function isSimpleCallArgument(node, depth = 2) {
779785

780786
if (isMemberExpression(node)) {
781787
return (
782-
isSimpleCallArgument(node.object, depth) &&
783-
isSimpleCallArgument(node.property, depth)
788+
isSimpleCallArgument(getChainProp(node, "object"), depth) &&
789+
isSimpleCallArgument(getChainProp(node, "property"), depth)
784790
);
785791
}
786792

@@ -1232,6 +1238,7 @@ export {
12321238
createTypeCheckFunction,
12331239
getCallArguments,
12341240
getCallArgumentSelector,
1241+
getChainProp,
12351242
getComments,
12361243
getFunctionParameters,
12371244
getLeftSide,

tests/format/js/chain-expression/__snapshots__/jsfmt.spec.js.snap

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,35 @@ test().test2().test2(thing?.something);
9797
================================================================================
9898
`;
9999
100+
exports[`issue-15916.js format 1`] = `
101+
====================================options=====================================
102+
parsers: ["babel", "typescript", "flow"]
103+
printWidth: 80
104+
| printWidth
105+
=====================================input======================================
106+
const randomFuncion = (value) => {
107+
if (value.a) {
108+
funcA(
109+
"",
110+
funcB(
111+
dayjs(value.a?.toString())
112+
.add(1, "day")
113+
.toISOString()
114+
)
115+
);
116+
}
117+
};
118+
119+
=====================================output=====================================
120+
const randomFuncion = (value) => {
121+
if (value.a) {
122+
funcA("", funcB(dayjs(value.a?.toString()).add(1, "day").toISOString()));
123+
}
124+
};
125+
126+
================================================================================
127+
`;
128+
100129
exports[`test.js format 1`] = `
101130
====================================options=====================================
102131
parsers: ["babel", "typescript", "flow"]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const randomFuncion = (value) => {
2+
if (value.a) {
3+
funcA(
4+
"",
5+
funcB(
6+
dayjs(value.a?.toString())
7+
.add(1, "day")
8+
.toISOString()
9+
)
10+
);
11+
}
12+
};

0 commit comments

Comments
 (0)