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 (#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.