diff --git a/changelog_unreleased/javascript/pr-6685.md b/changelog_unreleased/javascript/pr-6685.md
new file mode 100644
index 000000000..61246ec27
--- /dev/null
+++ b/changelog_unreleased/javascript/pr-6685.md
@@ -0,0 +1,22 @@
+#### Method chain breaking ([#6685](https://github.com/prettier/prettier/pull/6685) by [@mmkal](https://github.com/mmkal))
+
+Previously, any chained method calls of length three or longer would be automatically broken. This uses a heuristic for the complexity of the arguments in the chain, rather than just the chain length. Now, if chained method calls have arguments which aren't easy to understand at a glance (e.g. functions or deeply-nested objects), the chain is broken. Otherwise, they're allowed to remain on one line. See prior issues [#3197](https://github.com/prettier/prettier/issues/3107), [#4765](https://github.com/prettier/prettier/pull/4765), [#1565](https://github.com/prettier/prettier/issues/1565) and [#4125](https://github.com/prettier/prettier/pull/4125) for context and examples.
+
+
+```javascript
+// Input
+foo.one().two().three() === bar.four().five().six();
+
+// Output (Prettier stable)
+foo
+ .one()
+ .two()
+ .three() ===
+ bar
+ .four()
+ .five()
+ .six();
+
+// Output (Prettier master)
+foo.one().two().three() === bar.four().five().six();
+```
diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js
index 00b1e363b..eca7c19aa 100644
--- a/src/language-js/printer-estree.js
+++ b/src/language-js/printer-estree.js
@@ -76,6 +76,7 @@ const {
isNumericLiteral,
isObjectType,
isObjectTypePropertyAFunction,
+ isSimpleCallArgument,
isSimpleFlowType,
isSimpleTemplateLiteral,
isStringLiteral,
@@ -5084,9 +5085,7 @@ function printMemberChain(path, options, print) {
const oneLine = concat(printedGroups);
const cutoff = shouldMerge ? 3 : 2;
- const flatGroups = groups
- .slice(0, cutoff)
- .reduce((res, group) => res.concat(group), []);
+ const flatGroups = groups.reduce((res, group) => res.concat(group), []);
const hasComment =
flatGroups.slice(1, -1).some(node => hasLeadingComment(node.node)) ||
@@ -5123,14 +5122,17 @@ function printMemberChain(path, options, print) {
.map(({ node }) => node)
.filter(isCallOrOptionalCallExpression);
- // We don't want to print in one line if there's:
+ // We don't want to print in one line if the chain has:
// * A comment.
- // * 3 or more chained calls.
+ // * Non-trivial arguments.
// * Any group but the last one has a hard line.
// If the last group is a function it's okay to inline if it fits.
if (
hasComment ||
- callExpressions.length >= 3 ||
+ (callExpressions.length > 2 &&
+ callExpressions.some(
+ expr => !expr.arguments.every(arg => isSimpleCallArgument(arg, 0))
+ )) ||
printedGroups.slice(0, -1).some(willBreak) ||
/**
* scopes.filter(scope => scope.value !== '').map((scope, i) => {
diff --git a/src/language-js/utils.js b/src/language-js/utils.js
index fb51d4f2d..b27fa9901 100644
--- a/src/language-js/utils.js
+++ b/src/language-js/utils.js
@@ -885,6 +885,86 @@ function isLongCurriedCallExpression(path) {
);
}
+/**
+ * @param {import('estree').Node} node
+ * @param {number} depth
+ * @returns {boolean}
+ */
+function isSimpleCallArgument(node, depth) {
+ if (depth >= 2) {
+ return false;
+ }
+ const isChildSimple = child => isSimpleCallArgument(child, depth + 1);
+
+ const regexpPattern =
+ (node.type === "Literal" && node.regex && node.regex.pattern) ||
+ (node.type === "RegExpLiteral" && node.pattern);
+
+ if (regexpPattern && regexpPattern.length > 5) {
+ return false;
+ }
+
+ if (
+ node.type === "Literal" ||
+ node.type === "BooleanLiteral" ||
+ node.type === "NullLiteral" ||
+ node.type === "NumericLiteral" ||
+ node.type === "StringLiteral" ||
+ node.type === "Identifier" ||
+ node.type === "ThisExpression" ||
+ node.type === "Super" ||
+ node.type === "BigIntLiteral" ||
+ node.type === "PrivateName" ||
+ node.type === "ArgumentPlaceholder" ||
+ node.type === "RegExpLiteral" ||
+ node.type === "Import"
+ ) {
+ return true;
+ }
+ if (node.type === "TemplateLiteral") {
+ return node.expressions.every(isChildSimple);
+ }
+ if (node.type === "ObjectExpression") {
+ return node.properties.every(
+ p =>
+ p.shorthand ||
+ (isSimpleCallArgument(p.key, depth) && isChildSimple(p.value))
+ );
+ }
+ if (node.type === "ArrayExpression") {
+ return node.elements.every(isChildSimple);
+ }
+ if (
+ node.type === "CallExpression" ||
+ node.type === "OptionalCallExpression" ||
+ node.type === "NewExpression"
+ ) {
+ return (
+ isSimpleCallArgument(node.callee, depth) &&
+ node.arguments.every(isChildSimple)
+ );
+ }
+ if (
+ node.type === "MemberExpression" ||
+ node.type === "OptionalMemberExpression"
+ ) {
+ return (
+ isSimpleCallArgument(node.object, depth) &&
+ isSimpleCallArgument(node.property, depth)
+ );
+ }
+ if (
+ node.type === "UnaryExpression" &&
+ (node.operator === "!" || node.operator === "-")
+ ) {
+ return isSimpleCallArgument(node.argument, depth);
+ }
+ if (node.type === "TSNonNullExpression") {
+ return isSimpleCallArgument(node.expression, depth);
+ }
+ return false;
+}
+
function rawText(node) {
return node.extra ? node.extra.raw : node.raw;
}
@@ -930,6 +1010,7 @@ module.exports = {
isLastStatement,
isLiteral,
isLongCurriedCallExpression,
+ isSimpleCallArgument,
isMeaningfulJSXText,
isMemberExpressionChain,
isMemberish,
diff --git a/tests/flow/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap b/tests/flow/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap
index ad81f6583..401323dec 100644
--- a/tests/flow/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/flow/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap
@@ -76,10 +76,7 @@ let tests = [
hmac.update(buf, "utf8"); // 1 error: no encoding when passing a buffer
// it's also chainable
- (hmac
- .update("some data to hash")
- .update(buf)
- .digest(): Buffer);
+ (hmac.update("some data to hash").update(buf).digest(): Buffer);
(hmac.digest("hex"): string);
(hmac.digest(): Buffer);
diff --git a/tests/method-chain/__snapshots__/jsfmt.spec.js.snap b/tests/method-chain/__snapshots__/jsfmt.spec.js.snap
index fa915e143..94378d98e 100644
--- a/tests/method-chain/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/method-chain/__snapshots__/jsfmt.spec.js.snap
@@ -239,14 +239,9 @@ foo().bar().baz();
foo().bar.baz();
=====================================output=====================================
-object
- .foo()
- .bar()
- .baz();
+object.foo().bar().baz();
-foo()
- .bar()
- .baz();
+foo().bar().baz();
foo().bar.baz();
@@ -510,10 +505,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)
@@ -571,9 +563,7 @@ d3.select("body")
.at({ width: 30, fill: "#f0f" })
.st({ fontWeight: 600 });
-d3.scaleLinear()
- .domain([1950, 1980])
- .range([0, width]);
+d3.scaleLinear().domain([1950, 1980]).range([0, width]);
not.d3
.select("body")
@@ -581,10 +571,7 @@ not.d3
.at({ width: 30, fill: "#f0f" })
.st({ fontWeight: 600 });
-not.d3
- .scaleLinear()
- .domain([1950, 1980])
- .range([0, width]);
+not.d3.scaleLinear().domain([1950, 1980]).range([0, width]);
================================================================================
`;
@@ -708,9 +695,335 @@ this.layoutPartsToHide = this.utils.hashset(
.filter(Boolean)
);
-var jqxhr = $.ajax("example.php")
- .done(doneFn)
- .fail(failFn);
+var jqxhr = $.ajax("example.php").done(doneFn).fail(failFn);
+
+================================================================================
+`;
+
+exports[`issue-4125.js 1`] = `
+====================================options=====================================
+parsers: ["flow", "typescript"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+// examples from https://github.com/prettier/prettier/issues/4125
+
+const sha256 = (data) => crypto.createHash("sha256").update(data).digest("hex");
+
+req.checkBody('id').isInt().optional();
+req.checkBody('name').notEmpty().optional();
+
+const x = moment().add(1, 'day').valueOf()
+
+// should stay on one line:
+obj.foo(1).foo(2).foo(3);
+obj.foo(-1).foo(import('2')).foo(!x).check(/[A-Z]/);
+
+// better on multiple lines:
+somePromise.then(format).then((val)=>doSomething(val)).catch((err)=>handleError(err))
+
+// you can still force multi-line chaining with a comment:
+const sha256 = (data) =>
+ crypto // breakme
+ .createHash("sha256")
+ .update(data)
+ .digest("hex");
+
+// examples from https://github.com/prettier/prettier/pull/4765
+
+if ($(el).attr("href").includes("/wiki/")) {
+}
+
+if ($(el).attr("href").includes("/wiki/")) {
+ if ($(el).attr("xyz").includes("/whatever/")) {
+ if ($(el).attr("hello").includes("/world/")) {
+ }
+ }
+}
+
+const parseNumbers = s => s.split('').map(Number).sort()
+
+function palindrome(a, b) {
+ return a.slice().reverse().join(',') === b.slice().sort().join(',');
+}
+
+// examples from https://github.com/prettier/prettier/issues/1565
+
+d3.select("body").selectAll("p").data([1, 2, 3]).enter().style("color", "white");
+
+Object.keys(props).filter(key => key in own === false).reduce((a, key) => {
+ a[key] = props[key];
+ return a;
+}, {})
+
+point().x(4).y(3).z(6).plot();
+
+assert.equal(this.$().text().trim(), '1000');
+
+something().then(() => doSomethingElse()).then(result => dontForgetThisAsWell(result))
+
+db.branch(
+ db.table('users').filter({ email }).count(),
+ db.table('users').filter({ email: 'a@b.com' }).count(),
+ db.table('users').insert({ email }),
+ db.table('users').filter({ email }),
+)
+
+sandbox.stub(config, 'get').withArgs('env').returns('dev')
+
+moment.utc(userInput).hour(0).minute(0).second(0)
+
+fetchUser(id)
+ .then(fetchAccountForUser)
+ .catch(handleFetchError)
+
+fetchUser(id) //
+ .then(fetchAccountForUser)
+ .catch(handleFetchError)
+
+// examples from https://github.com/prettier/prettier/issues/3107
+
+function HelloWorld() {
+ window.FooClient.setVars({
+ locale: getFooLocale({ page }),
+ authorizationToken: data.token,
+ }).initVerify('foo_container');
+
+ fejax.ajax({
+ url: '/verification/',
+ dataType: 'json',
+ }).then(
+ (data) => {
+ this.setState({ isLoading: false });
+ this.initWidget(data);
+ },
+ (data) => {
+ this.logImpression('foo_fetch_error', data);
+ Flash.error(I18n.t('offline_identity.foo_issue'));
+ },
+ );
+}
+
+action$.ofType(ActionTypes.SEARCHED_USERS)
+ .map(action => action.payload.query)
+ .filter(q => !!q)
+ .switchMap(q =>
+ Observable.timer(800) // debounce
+ .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS))
+ .mergeMap(() =>
+ Observable.merge(
+ Observable.of(replace(\`?q=\${q}\`)),
+ ajax
+ .getJSON(\`https://api.github.com/search/users?q=\${q}\`)
+ .map(res => res.items)
+ .map(receiveUsers)
+ )
+ )
+ );
+
+window.FooClient
+ .setVars({
+ locale: getFooLocale({ page }),
+ authorizationToken: data.token,
+ })
+ .initVerify('foo_container');
+
+it('gets triggered by mouseenter', () => {
+ const wrapper = shallow();
+ wrapper.dive().find(Button).prop();
+});
+
+x.a(true).b(null).c(123)
+x.d('').e(\`\`).f(g)
+x.d('').e(\`\${123}\`).f(g)
+x.h(i.j).k(l()).m([n, o])
+class X {
+ y() {
+ x.a(this).b(super.cde()).f(/g/).h(new i()).j()
+ }
+}
+
+// should break when call expressions get complex
+x.a().b([c, [d, [e]]]).f()
+x.a().b(c(d(e()))).f()
+x.a().b(\`\${c(d())}\`).f()
+
+xyz.a().b().c(a(a(b(c(d().p).p).p).p))
+
+var l = base
+ .replace(/^\\w*:\\/\\//, '')
+ .replace(/\\/$/, '')
+ .split('/').length
+
+
+=====================================output=====================================
+// examples from https://github.com/prettier/prettier/issues/4125
+
+const sha256 = data => crypto.createHash("sha256").update(data).digest("hex");
+
+req.checkBody("id").isInt().optional();
+req.checkBody("name").notEmpty().optional();
+
+const x = moment().add(1, "day").valueOf();
+
+// should stay on one line:
+obj.foo(1).foo(2).foo(3);
+obj.foo(-1).foo(import("2")).foo(!x).check(/[A-Z]/);
+
+// better on multiple lines:
+somePromise
+ .then(format)
+ .then(val => doSomething(val))
+ .catch(err => handleError(err));
+
+// you can still force multi-line chaining with a comment:
+const sha256 = data =>
+ crypto // breakme
+ .createHash("sha256")
+ .update(data)
+ .digest("hex");
+
+// examples from https://github.com/prettier/prettier/pull/4765
+
+if ($(el).attr("href").includes("/wiki/")) {
+}
+
+if ($(el).attr("href").includes("/wiki/")) {
+ if ($(el).attr("xyz").includes("/whatever/")) {
+ if ($(el).attr("hello").includes("/world/")) {
+ }
+ }
+}
+
+const parseNumbers = s => s.split("").map(Number).sort();
+
+function palindrome(a, b) {
+ return a.slice().reverse().join(",") === b.slice().sort().join(",");
+}
+
+// examples from https://github.com/prettier/prettier/issues/1565
+
+d3.select("body")
+ .selectAll("p")
+ .data([1, 2, 3])
+ .enter()
+ .style("color", "white");
+
+Object.keys(props)
+ .filter(key => key in own === false)
+ .reduce((a, key) => {
+ a[key] = props[key];
+ return a;
+ }, {});
+
+point().x(4).y(3).z(6).plot();
+
+assert.equal(this.$().text().trim(), "1000");
+
+something()
+ .then(() => doSomethingElse())
+ .then(result => dontForgetThisAsWell(result));
+
+db.branch(
+ db.table("users").filter({ email }).count(),
+ db.table("users").filter({ email: "a@b.com" }).count(),
+ db.table("users").insert({ email }),
+ db.table("users").filter({ email })
+);
+
+sandbox.stub(config, "get").withArgs("env").returns("dev");
+
+moment.utc(userInput).hour(0).minute(0).second(0);
+
+fetchUser(id).then(fetchAccountForUser).catch(handleFetchError);
+
+fetchUser(id) //
+ .then(fetchAccountForUser)
+ .catch(handleFetchError);
+
+// examples from https://github.com/prettier/prettier/issues/3107
+
+function HelloWorld() {
+ window.FooClient.setVars({
+ locale: getFooLocale({ page }),
+ authorizationToken: data.token,
+ }).initVerify("foo_container");
+
+ fejax
+ .ajax({
+ url: "/verification/",
+ dataType: "json",
+ })
+ .then(
+ data => {
+ this.setState({ isLoading: false });
+ this.initWidget(data);
+ },
+ data => {
+ this.logImpression("foo_fetch_error", data);
+ Flash.error(I18n.t("offline_identity.foo_issue"));
+ }
+ );
+}
+
+action$
+ .ofType(ActionTypes.SEARCHED_USERS)
+ .map(action => action.payload.query)
+ .filter(q => !!q)
+ .switchMap(q =>
+ Observable.timer(800) // debounce
+ .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS))
+ .mergeMap(() =>
+ Observable.merge(
+ Observable.of(replace(\`?q=\${q}\`)),
+ ajax
+ .getJSON(\`https://api.github.com/search/users?q=\${q}\`)
+ .map(res => res.items)
+ .map(receiveUsers)
+ )
+ )
+ );
+
+window.FooClient.setVars({
+ locale: getFooLocale({ page }),
+ authorizationToken: data.token,
+}).initVerify("foo_container");
+
+it("gets triggered by mouseenter", () => {
+ const wrapper = shallow();
+ wrapper.dive().find(Button).prop();
+});
+
+x.a(true).b(null).c(123);
+x.d("").e(\`\`).f(g);
+x.d("").e(\`\${123}\`).f(g);
+x.h(i.j).k(l()).m([n, o]);
+class X {
+ y() {
+ x.a(this).b(super.cde()).f(/g/).h(new i()).j();
+ }
+}
+
+// should break when call expressions get complex
+x.a()
+ .b([c, [d, [e]]])
+ .f();
+x.a()
+ .b(c(d(e())))
+ .f();
+x.a()
+ .b(\`\${c(d())}\`)
+ .f();
+
+xyz
+ .a()
+ .b()
+ .c(a(a(b(c(d().p).p).p).p));
+
+var l = base
+ .replace(/^\\w*:\\/\\//, "")
+ .replace(/\\/$/, "")
+ .split("/").length;
================================================================================
`;
@@ -813,16 +1126,14 @@ if (testConfig.ENABLE_ONLINE_TESTS === "true") {
describe("POST /users/me/pet", function() {
it("saves pet", function() {
function assert(pet) {
- expect(pet)
- .to.have.property("OwnerAddress")
- .that.deep.equals({
- AddressLine1: "Alexanderstrasse",
- AddressLine2: "",
- PostalCode: "10999",
- Region: "Berlin",
- City: "Berlin",
- Country: "DE",
- });
+ expect(pet).to.have.property("OwnerAddress").that.deep.equals({
+ AddressLine1: "Alexanderstrasse",
+ AddressLine2: "",
+ PostalCode: "10999",
+ Region: "Berlin",
+ City: "Berlin",
+ Country: "DE",
+ });
}
});
});
diff --git a/tests/method-chain/issue-4125.js b/tests/method-chain/issue-4125.js
new file mode 100644
index 000000000..0f755ba12
--- /dev/null
+++ b/tests/method-chain/issue-4125.js
@@ -0,0 +1,149 @@
+// examples from https://github.com/prettier/prettier/issues/4125
+
+const sha256 = (data) => crypto.createHash("sha256").update(data).digest("hex");
+
+req.checkBody('id').isInt().optional();
+req.checkBody('name').notEmpty().optional();
+
+const x = moment().add(1, 'day').valueOf()
+
+// should stay on one line:
+obj.foo(1).foo(2).foo(3);
+obj.foo(-1).foo(import('2')).foo(!x).check(/[A-Z]/);
+
+// better on multiple lines:
+somePromise.then(format).then((val)=>doSomething(val)).catch((err)=>handleError(err))
+
+// you can still force multi-line chaining with a comment:
+const sha256 = (data) =>
+ crypto // breakme
+ .createHash("sha256")
+ .update(data)
+ .digest("hex");
+
+// examples from https://github.com/prettier/prettier/pull/4765
+
+if ($(el).attr("href").includes("/wiki/")) {
+}
+
+if ($(el).attr("href").includes("/wiki/")) {
+ if ($(el).attr("xyz").includes("/whatever/")) {
+ if ($(el).attr("hello").includes("/world/")) {
+ }
+ }
+}
+
+const parseNumbers = s => s.split('').map(Number).sort()
+
+function palindrome(a, b) {
+ return a.slice().reverse().join(',') === b.slice().sort().join(',');
+}
+
+// examples from https://github.com/prettier/prettier/issues/1565
+
+d3.select("body").selectAll("p").data([1, 2, 3]).enter().style("color", "white");
+
+Object.keys(props).filter(key => key in own === false).reduce((a, key) => {
+ a[key] = props[key];
+ return a;
+}, {})
+
+point().x(4).y(3).z(6).plot();
+
+assert.equal(this.$().text().trim(), '1000');
+
+something().then(() => doSomethingElse()).then(result => dontForgetThisAsWell(result))
+
+db.branch(
+ db.table('users').filter({ email }).count(),
+ db.table('users').filter({ email: 'a@b.com' }).count(),
+ db.table('users').insert({ email }),
+ db.table('users').filter({ email }),
+)
+
+sandbox.stub(config, 'get').withArgs('env').returns('dev')
+
+moment.utc(userInput).hour(0).minute(0).second(0)
+
+fetchUser(id)
+ .then(fetchAccountForUser)
+ .catch(handleFetchError)
+
+fetchUser(id) //
+ .then(fetchAccountForUser)
+ .catch(handleFetchError)
+
+// examples from https://github.com/prettier/prettier/issues/3107
+
+function HelloWorld() {
+ window.FooClient.setVars({
+ locale: getFooLocale({ page }),
+ authorizationToken: data.token,
+ }).initVerify('foo_container');
+
+ fejax.ajax({
+ url: '/verification/',
+ dataType: 'json',
+ }).then(
+ (data) => {
+ this.setState({ isLoading: false });
+ this.initWidget(data);
+ },
+ (data) => {
+ this.logImpression('foo_fetch_error', data);
+ Flash.error(I18n.t('offline_identity.foo_issue'));
+ },
+ );
+}
+
+action$.ofType(ActionTypes.SEARCHED_USERS)
+ .map(action => action.payload.query)
+ .filter(q => !!q)
+ .switchMap(q =>
+ Observable.timer(800) // debounce
+ .takeUntil(action$.ofType(ActionTypes.CLEARED_SEARCH_RESULTS))
+ .mergeMap(() =>
+ Observable.merge(
+ Observable.of(replace(`?q=${q}`)),
+ ajax
+ .getJSON(`https://api.github.com/search/users?q=${q}`)
+ .map(res => res.items)
+ .map(receiveUsers)
+ )
+ )
+ );
+
+window.FooClient
+ .setVars({
+ locale: getFooLocale({ page }),
+ authorizationToken: data.token,
+ })
+ .initVerify('foo_container');
+
+it('gets triggered by mouseenter', () => {
+ const wrapper = shallow();
+ wrapper.dive().find(Button).prop();
+});
+
+x.a(true).b(null).c(123)
+x.d('').e(``).f(g)
+x.d('').e(`${123}`).f(g)
+x.h(i.j).k(l()).m([n, o])
+class X {
+ y() {
+ x.a(this).b(super.cde()).f(/g/).h(new i()).j()
+ }
+}
+
+// should break when call expressions get complex
+x.a().b([c, [d, [e]]]).f()
+x.a().b(c(d(e()))).f()
+x.a().b(`${c(d())}`).f()
+
+xyz.a().b().c(a(a(b(c(d().p).p).p).p))
+
+var l = base
+ .replace(/^\w*:\/\//, '')
+ .replace(/\/$/, '')
+ .split('/').length
+
diff --git a/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap b/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap
index 5fc1e5621..c3a88f597 100644
--- a/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/test_declarations/__snapshots__/jsfmt.spec.js.snap
@@ -46,21 +46,13 @@ beforeEach(async(() => {
// code
}));
-beforeEach(done =>
- foo()
- .bar()
- .bar()
-);
+beforeEach(done => foo().bar().bar());
afterAll(async(() => {
console.log("Hello");
}));
-afterAll(done =>
- foo()
- .bar()
- .bar()
-);
+afterAll(done => foo().bar().bar());
it("should create the app", async(() => {
//code
@@ -129,21 +121,13 @@ beforeEach(async(() => {
// code
}));
-beforeEach((done) =>
- foo()
- .bar()
- .bar()
-);
+beforeEach((done) => foo().bar().bar());
afterAll(async(() => {
console.log("Hello");
}));
-afterAll((done) =>
- foo()
- .bar()
- .bar()
-);
+afterAll((done) => foo().bar().bar());
it("should create the app", async(() => {
//code
@@ -477,7 +461,7 @@ describe.each\`a | b | expected
// an example to demo multiline quasi
describe.each\`a | b | expected
-\${11111111111} | \${a().b().c().d()} | \${2}
+\${11111111111} | \${a().b(x => x).c().d()} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}\`
@@ -545,7 +529,7 @@ describe.each\`
describe.each\`
a | b | expected
\${11111111111} | \${a()
- .b()
+ .b(x => x)
.c()
.d()} | \${2}
\${1} | \${2} | \${3}
@@ -622,7 +606,7 @@ describe.each\`a | b | expected
// an example to demo multiline quasi
describe.each\`a | b | expected
-\${11111111111} | \${a().b().c().d()} | \${2}
+\${11111111111} | \${a().b(x => x).c().d()} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}\`
@@ -690,7 +674,7 @@ describe.each\`
describe.each\`
a | b | expected
\${11111111111} | \${a()
- .b()
+ .b((x) => x)
.c()
.d()} | \${2}
\${1} | \${2} | \${3}
diff --git a/tests/test_declarations/jest-each.js b/tests/test_declarations/jest-each.js
index 8bcdf7fb4..246b25bd9 100644
--- a/tests/test_declarations/jest-each.js
+++ b/tests/test_declarations/jest-each.js
@@ -38,7 +38,7 @@ ${2} | ${1} | ${3}`
// an example to demo multiline quasi
describe.each`a | b | expected
-${11111111111} | ${a().b().c().d()} | ${2}
+${11111111111} | ${a().b(x => x).c().d()} | ${2}
${1} | ${2} | ${3}
${2} | ${1} | ${3}`
diff --git a/tests/typescript_non_null/__snapshots__/jsfmt.spec.js.snap b/tests/typescript_non_null/__snapshots__/jsfmt.spec.js.snap
index b0fc7499a..0442353ca 100644
--- a/tests/typescript_non_null/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/typescript_non_null/__snapshots__/jsfmt.spec.js.snap
@@ -25,15 +25,9 @@ const {
anotherPropThatHasALongName2,
} = this.props.imReallySureAboutThis!.anotherObject;
-this.foo
- .get("bar")!
- .doThings()
- .more();
+this.foo.get("bar")!.doThings().more();
-foo!
- .bar()
- .baz()
- .what();
+foo!.bar().baz().what();
================================================================================
`;
@@ -68,6 +62,8 @@ new (x()\`\`!.y)();
new (x()!\`\`.y)();
new (x!()\`\`.y)();
+xyz.a(b!).a(b!).a(b!)
+
=====================================output=====================================
(a ? b : c)![tokenKey];
(a || b)![tokenKey];
@@ -93,5 +89,7 @@ new (x()\`\`!.y)();
new (x()!\`\`.y)();
new (x!()\`\`.y)();
+xyz.a(b!).a(b!).a(b!);
+
================================================================================
`;
diff --git a/tests/typescript_non_null/parens.ts b/tests/typescript_non_null/parens.ts
index 3f064920e..ef13c0346 100644
--- a/tests/typescript_non_null/parens.ts
+++ b/tests/typescript_non_null/parens.ts
@@ -21,3 +21,5 @@ new (x()``.y!)();
new (x()``!.y)();
new (x()!``.y)();
new (x!()``.y)();
+
+xyz.a(b!).a(b!).a(b!)