Skip to content

Commit

Permalink
Make chain breaking as similar to original prettier (js) as much as p…
Browse files Browse the repository at this point in the history
…ossible (prettier#2320)

* Removed chain break with more than 3 expressions

* Added maxChainCallExpressionCountPHP option to control max calls in a chain

* Added option to readme
Updated description in options file

* Added advance check for chain breaks

* Reduced chain items count to 2 for complexity test
Fixed array handling in complexity test

* Func. name change

* Removed comment

* Style fix

---------

Co-authored-by: Kristijan Novaković <[email protected]>
  • Loading branch information
eldair and eldair authored Feb 3, 2024
1 parent c8aadcf commit 410e292
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 146 deletions.
12 changes: 8 additions & 4 deletions src/printer.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
getAncestorNode,
isReferenceLikeNode,
normalizeMagicMethodName,
isSimpleCallArgument,
} from "./util.mjs";

const {
Expand Down Expand Up @@ -508,9 +509,9 @@ function printMemberChain(path, options, print) {
printIndentedGroup(groups.slice(shouldMerge ? 2 : 1)),
];

const callExpressionCount = printedNodes.filter(
(tuple) => tuple.node.kind === "call"
).length;
const callExpressions = printedNodes.filter((tuple) =>
["call", "new"].includes(tuple.node.kind)
);

// We don't want to print in one line if there's:
// * A comment.
Expand All @@ -519,7 +520,10 @@ function printMemberChain(path, options, print) {
// If the last group is a function it's okay to inline if it fits.
if (
hasComment ||
callExpressionCount >= 3 ||
(callExpressions.length > 2 &&
callExpressions.some(
(exp) => !exp.node.arguments.every((arg) => isSimpleCallArgument(arg))
)) ||
printedGroups.slice(0, -1).some(willBreak)
) {
return group(expanded);
Expand Down
74 changes: 74 additions & 0 deletions src/util.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,79 @@ function normalizeMagicMethodName(name) {
return name;
}

/**
* @param {string[]} kindsArray
* @returns {(node: Node | Comment) => Boolean}
*/
function createTypeCheckFunction(kindsArray) {
const kinds = new Set(kindsArray);
return (node) => kinds.has(node?.kind);
}

const isSingleWordType = createTypeCheckFunction([
"variable",
"parameter",
"variadic",
"clone",
"cast",
"boolean",
"number",
"string",
"literal",
"nullkeyword",
"namedargument",
"variadicplaceholder",
]);

const isArrayExpression = createTypeCheckFunction(["array"]);
const isCallOrNewExpression = createTypeCheckFunction(["call", "new"]);
const isArrowFuncExpression = createTypeCheckFunction(["arrowfunc"]);

function getChainParts(node, prev = []) {
const parts = prev;
if (isCallOrNewExpression(node)) {
parts.push(node);
}

if (!node.what) {
return parts;
}

return getChainParts(node.what, parts);
}

function isSimpleCallArgument(node, depth = 2) {
if (depth <= 0) {
return false;
}

const isChildSimple = (child) => isSimpleCallArgument(child, depth - 1);

if (isSingleWordType(node)) {
return true;
}

if (isArrayExpression(node)) {
return node.items.every((x) => x === null || isChildSimple(x));
}

if (isCallOrNewExpression(node)) {
const parts = getChainParts(node);
return (
parts.filter((node) => node.kind === "call").length <= depth &&
parts.every((node) => node.arguments.every(isChildSimple))
);
}

if (isArrowFuncExpression(node)) {
return (
node.arguments.length <= depth && node.arguments.every(isChildSimple)
);
}

return false;
}

export {
printNumber,
getPrecedence,
Expand Down Expand Up @@ -641,4 +714,5 @@ export {
isDocNode,
getAncestorNode,
normalizeMagicMethodName,
isSimpleCallArgument,
};
19 changes: 3 additions & 16 deletions tests/call/__snapshots__/jsfmt.spec.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -705,18 +705,8 @@ $var = $this->foo()();
$var = ($this->foo->bar)();
$var = $this->foo->bar()();
$var = ($this->foo->bar->baz->foo->bar->baz)();
$var = $this->foo()
->bar()
->baz()
->foo()
->bar()
->baz()();
$var = ($this->foo()
->bar()
->baz()
->foo()
->bar()
->baz)();
$var = $this->foo()->bar()->baz()->foo()->bar()->baz()();
$var = ($this->foo()->bar()->baz()->foo()->bar()->baz)();
$var = $this["foo"]();
$var = $this["foo"]["bar"]();
$var = ($this::$foo)();
Expand All @@ -733,10 +723,7 @@ $var = ((["Foo", "bar"])->bar)();
$var = ($var->foo)()();
$var = ($var->foo)()();
$var = (($var->foo)()->bar)();
$var = ((($var
->foo)()
->bar)()
->baz)();
$var = ((($var->foo)()->bar)()->baz)();
$obj = call('return new class($value)
{
Expand Down
130 changes: 50 additions & 80 deletions tests/member_chain/__snapshots__/jsfmt.spec.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,47 @@ printWidth: 80
$object->foo()->bar()->baz();
$object->foo()->bar()->baz()->foo()->bar()->baz();
$object->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz();
$object->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz();
foo()->bar()->baz();
foo()->bar->baz();
=====================================output=====================================
<?php
$object->foo()->bar()->baz();
$object->foo()->bar()->baz()->foo()->bar()->baz();
$object->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz();
$object
->foo()
->bar()
->baz();
foo()
->baz()
->foo()
->bar()
->baz()
->foo()
->bar()
->baz()
->foo()
->bar()
->baz()
->foo()
->bar()
->baz()
->foo()
->bar()
->baz();
foo()->bar()->baz();
foo()->bar->baz();
================================================================================
Expand Down Expand Up @@ -191,10 +216,7 @@ $object[$valid
($a ? $b : $c)->d()->e();
($a ? $b : $c)
->d()
->e()
->f();
($a ? $b : $c)->d()->e()->f();
($valid
? $helper->responseBody($this->currentUser)
Expand Down Expand Up @@ -436,12 +458,8 @@ $var = Foo::keys($items)->filter(function ($x) { return $x > 2; })->map(function
<?php
one()->two();
one()
->two()
->three();
one()
->two->three()
->four->five();
one()->two()->three();
one()->two->three()->four->five();
Route::prefix("api")
->middleware("api")
Expand Down Expand Up @@ -476,9 +494,7 @@ $a->a()->b();
$a->a()->b();
$a->a()->b;
$a->b->a();
$a->b()
->c()
->d();
$a->b()->c()->d();
$a->b->c->d;
// should inline
Expand Down Expand Up @@ -545,67 +561,19 @@ $foo->bar(
"veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLong"
)()()()()();
$brian->hotel
->orders()
->ordered()
->with("smith")
->get();
$brian::$hotel
->orders()
->ordered()
->with("smith")
->get();
$brian["hotel"]
->orders()
->ordered()
->with("smith")
->get();
Foo::$hotel
->orders()
->ordered()
->with("smith")
->get();
(new Foo())->hotel
->orders()
->ordered()
->with("smith")
->get();
(clone $a)->hotel
->orders()
->ordered()
->with("smith")
->get();
$var = $brian->hotel
->orders()
->ordered()
->with("smith")
->get();
$var = $brian::$hotel
->orders()
->ordered()
->with("smith")
->get();
$var = $brian["hotel"]
->orders()
->ordered()
->with("smith")
->get();
$var = Foo::$hotel
->orders()
->ordered()
->with("smith")
->get();
$var = (new Foo())->hotel
->orders()
->ordered()
->with("smith")
->get();
$var = (clone $a)->hotel
->orders()
->ordered()
->with("smith")
->get();
$brian->hotel->orders()->ordered()->with("smith")->get();
$brian::$hotel->orders()->ordered()->with("smith")->get();
$brian["hotel"]->orders()->ordered()->with("smith")->get();
Foo::$hotel->orders()->ordered()->with("smith")->get();
(new Foo())->hotel->orders()->ordered()->with("smith")->get();
(clone $a)->hotel->orders()->ordered()->with("smith")->get();
$var = $brian->hotel->orders()->ordered()->with("smith")->get();
$var = $brian::$hotel->orders()->ordered()->with("smith")->get();
$var = $brian["hotel"]->orders()->ordered()->with("smith")->get();
$var = Foo::$hotel->orders()->ordered()->with("smith")->get();
$var = (new Foo())->hotel->orders()->ordered()->with("smith")->get();
$var = (clone $a)->hotel->orders()->ordered()->with("smith")->get();
$var = Foo::keys($items)
->filter(function ($x) {
Expand All @@ -615,9 +583,11 @@ $var = Foo::keys($items)
return $x * 2;
});
(new static(func_get_args()))->push($this)->each(function ($item) {
VarDumper::dump($item);
});
(new static(func_get_args()))
->push($this)
->each(function ($item) {
VarDumper::dump($item);
});
(new static(func_get_args()))
->offset(10)
->push($this)
Expand Down
6 changes: 6 additions & 0 deletions tests/member_chain/break-multiple.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

$object->foo()->bar()->baz();

$object->foo()->bar()->baz()->foo()->bar()->baz();

$object->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz();

$object->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz()->foo()->bar()->baz();

foo()->bar()->baz();

foo()->bar->baz();
15 changes: 3 additions & 12 deletions tests/parens/__snapshots__/jsfmt.spec.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1568,10 +1568,7 @@ $var = (clone foo())->bar()->foo();
$var = (clone foo())->bar()->foo();
$var = (clone foo())->bar()->foo()[0];
$var = (clone foo())->bar()->foo()[0][1];
$var = (clone foo())
->bar()
->foo()
->baz();
$var = (clone foo())->bar()->foo()->baz();
$var = (clone $foo())->bar;
$var = (clone $bar->y)->x;
$var = (clone $foo)[0];
Expand Down Expand Up @@ -2562,10 +2559,7 @@ $var = (new foo())->bar()->foo();
$var = (new foo())->bar()->foo();
$var = (new foo())->bar()->foo()[0];
$var = (new foo())->bar()->foo()[0][1];
$var = (new foo())
->bar()
->foo()
->baz();
$var = (new foo())->bar()->foo()->baz();
$var = (new $foo())->bar;
$var = (new $bar->y())->x;
$var = (new foo())[0];
Expand Down Expand Up @@ -2935,10 +2929,7 @@ $var = ((int) $var) + 1 === 2 ? "1" : "2";
($var ? $var : $var)[1];
($var ? $var : $var)->d();
($var ? $var : $var)->d()->e();
($var ? $var : $var)
->d()
->e()
->f();
($var ? $var : $var)->d()->e()->f();
($var
? $var->responseBody($var->currentUser)
: $var->responseBody($var->defaultUser)
Expand Down
5 changes: 1 addition & 4 deletions tests/print/__snapshots__/jsfmt.spec.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,7 @@ print $var->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty
->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty
->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty;
print $var
->call()
->call()
->call();
print $var->call()->call()->call();
print $var
->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongCall()
->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongCall()
Expand Down
Loading

0 comments on commit 410e292

Please sign in to comment.