diff --git a/.node-version b/.node-version
new file mode 100644
index 000000000..b460d6f2d
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+18.12.1
diff --git a/tests/format/js/conditional/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/conditional/__snapshots__/jsfmt.spec.js.snap
index 52296ec2f..31cbd272f 100644
--- a/tests/format/js/conditional/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/js/conditional/__snapshots__/jsfmt.spec.js.snap
@@ -94,6 +94,7 @@ test
comment
comment
comment
+ A newline will be added after this comment, unfortunately – but it can be removed manually, see next statement.
*/
test
? foo
@@ -103,6 +104,23 @@ test
*/
bar;
+
+// It is at least possible to delete the extra newline that was
+// unfortunately added before the second condition above:
+test ?
+ foo :/* comment
+ comment
+ comment
+ comment
+ */
+test ?
+ foo :
+ /* comment
+ comment
+ comment
+ */
+ bar;
+
test
? foo
: /* comment */
@@ -200,6 +218,7 @@ test
comment
comment
comment
+ A newline will be added after this comment, unfortunately – but it can be removed manually, see next statement.
*/
test
? foo
@@ -209,6 +228,22 @@ test
*/
bar;
+// It is at least possible to delete the extra newline that was
+// unfortunately added before the second condition above:
+test
+ ? foo /* comment
+ comment
+ comment
+ comment
+ */
+ : test
+ ? foo
+ : /* comment
+ comment
+ comment
+ */
+ bar;
+
test ? foo : /* comment */ bar;
test
@@ -239,6 +274,699 @@ const testConsole = new TestConsole(
================================================================================
`;
+exports[`new-ternary-examples.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+// from https://gist.github.com/rattrayalex/dacbf5838571a47f22d0ae1f8b960268
+// Input and output should match (for 2-space indent formatting).
+// TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts
+// EXAMPLES
+// mostly taken from https://github.com/prettier/prettier/issues/9561
+
+const message =
+ i % 3 === 0 && i % 5 === 0 ? "fizzbuzz"
+ : i % 3 === 0 ? "fizz"
+ : i % 5 === 0 ? "buzz"
+ : String(i);
+
+const paymentMessageShort =
+ state == "success" ? "Payment completed successfully"
+ : state == "processing" ? "Payment processing"
+ : state == "invalid_cvc" ? "There was an issue with your CVC number"
+ : state == "invalid_expiry" ? "Expiry must be sometime in the past."
+ : "There was an issue with the payment. Please contact support.";
+
+const paymentMessageWithABreak =
+ state == "success" ? "Payment completed successfully"
+ : state == "processing" ? "Payment processing"
+ : state == "invalid_cvc" ?
+ "There was an issue with your CVC number, and you need to take a prompt action on it."
+ : state == "invalid_expiry" ? "Expiry must be sometime in the past."
+ : "There was an issue with the payment. Please contact support.";
+
+const typeofExample =
+ definition.encode ?
+ definition.encode(
+ typeof row[field] !== "undefined" ? row[field]
+ : typeof definition.default !== "undefined" ? definition.default
+ : null
+ )
+ : typeof row[field] !== "undefined" ? row[field]
+ : typeof definition.default !== "undefined" ? definition.default
+ : null
+
+// (the following is semantically equivalent to the above, but written in a more-confusing style – it'd be hard to grok no matter the formatting)
+const typeofExampleFlipped =
+ definition.encode ?
+ definition.encode(
+ typeof row[field] === "undefined" ?
+ typeof definition.default === "undefined" ? null
+ : definition.default
+ : row[field]
+ )
+ : typeof row[field] === "undefined" ?
+ typeof definition.default === "undefined" ? null
+ : definition.default
+ : row[field];
+
+
+// JSX Examples:
+
+const typicalLongConsequentWithNullAlternate = (
+
+ {children && !isEmptyChildren(children) ?
+
+ : null}
+
+);
+
+const reactRouterExampleJSX = (
+
+ {children && !isEmptyChildren(children) ?
+ children
+ : props.match ?
+ component ? React.createElement(component, props)
+ : render ? render(props)
+ : null
+ : null}
+
+);
+
+const reactRouterExampleNonJSX =
+ children && !isEmptyChildren(children) ? children
+ : props.match ?
+ component ? React.createElement(component, props)
+ : render ? render(props)
+ : null
+ : null;
+
+inJSXExpressionContainer.withLongConditionals.example = (
+
+ {(
+ isACat() &&
+ (someReallyLongCondition ||
+ moreInThisLongCondition)
+ ) ?
+ someReallyLargeExpression
+ .toMakeMeowNoise()
+ .willCauseParens()
+ : (
+ someReallyLongCondition ||
+ moreInThisLongCondition
+ ) ?
+ bark()
+ : someReallyLargeExpression
+ .toMakeMeowNoise()
+ .willCauseParens()
+ }
+
+);
+
+inJSXExpressionContainer.withLoops.orBooleans.example = (
+
+ {items ?
+ items.map((item) => (
+ item.display ?
+
+ :
+ ))
+ : null}
+
+ {showTheStuff && (
+ foo ?
+
+ :
+ )}
+
+);
+
+inJSXExpressionContainer.withNullConditional = (
+
+ {isACat() ? null : }
+ {isACat() && (someReallyLongCondition || moreInThisLongCondition) ? null : (
+
+ )}
+ {isACat() && (someReallyLongCondition || moreInThisLongCondition || evenMoreInThisExtraLongConditional) ? null : (
+
+ )}
+
+);
+
+=====================================output=====================================
+// from https://gist.github.com/rattrayalex/dacbf5838571a47f22d0ae1f8b960268
+// Input and output should match (for 2-space indent formatting).
+// TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts
+// EXAMPLES
+// mostly taken from https://github.com/prettier/prettier/issues/9561
+
+const message =
+ i % 3 === 0 && i % 5 === 0
+ ? "fizzbuzz"
+ : i % 3 === 0
+ ? "fizz"
+ : i % 5 === 0
+ ? "buzz"
+ : String(i);
+
+const paymentMessageShort =
+ state == "success"
+ ? "Payment completed successfully"
+ : state == "processing"
+ ? "Payment processing"
+ : state == "invalid_cvc"
+ ? "There was an issue with your CVC number"
+ : state == "invalid_expiry"
+ ? "Expiry must be sometime in the past."
+ : "There was an issue with the payment. Please contact support.";
+
+const paymentMessageWithABreak =
+ state == "success"
+ ? "Payment completed successfully"
+ : state == "processing"
+ ? "Payment processing"
+ : state == "invalid_cvc"
+ ? "There was an issue with your CVC number, and you need to take a prompt action on it."
+ : state == "invalid_expiry"
+ ? "Expiry must be sometime in the past."
+ : "There was an issue with the payment. Please contact support.";
+
+const typeofExample = definition.encode
+ ? definition.encode(
+ typeof row[field] !== "undefined"
+ ? row[field]
+ : typeof definition.default !== "undefined"
+ ? definition.default
+ : null
+ )
+ : typeof row[field] !== "undefined"
+ ? row[field]
+ : typeof definition.default !== "undefined"
+ ? definition.default
+ : null;
+
+// (the following is semantically equivalent to the above, but written in a more-confusing style – it'd be hard to grok no matter the formatting)
+const typeofExampleFlipped = definition.encode
+ ? definition.encode(
+ typeof row[field] === "undefined"
+ ? typeof definition.default === "undefined"
+ ? null
+ : definition.default
+ : row[field]
+ )
+ : typeof row[field] === "undefined"
+ ? typeof definition.default === "undefined"
+ ? null
+ : definition.default
+ : row[field];
+
+// JSX Examples:
+
+const typicalLongConsequentWithNullAlternate = (
+
+ {children && !isEmptyChildren(children) ? (
+
+ ) : null}
+
+);
+
+const reactRouterExampleJSX = (
+
+ {children && !isEmptyChildren(children)
+ ? children
+ : props.match
+ ? component
+ ? React.createElement(component, props)
+ : render
+ ? render(props)
+ : null
+ : null}
+
+);
+
+const reactRouterExampleNonJSX =
+ children && !isEmptyChildren(children)
+ ? children
+ : props.match
+ ? component
+ ? React.createElement(component, props)
+ : render
+ ? render(props)
+ : null
+ : null;
+
+inJSXExpressionContainer.withLongConditionals.example = (
+
+ {isACat() && (someReallyLongCondition || moreInThisLongCondition)
+ ? someReallyLargeExpression.toMakeMeowNoise().willCauseParens()
+ : someReallyLongCondition || moreInThisLongCondition
+ ? bark()
+ : someReallyLargeExpression.toMakeMeowNoise().willCauseParens()}
+
+);
+
+inJSXExpressionContainer.withLoops.orBooleans.example = (
+
+ {items
+ ? items.map((item) =>
+ item.display ? (
+
+ ) : (
+
+ )
+ )
+ : null}
+
+ {showTheStuff &&
+ (foo ? (
+
+ ) : (
+
+ ))}
+
+);
+
+inJSXExpressionContainer.withNullConditional = (
+
+ {isACat() ? null : }
+ {isACat() && (someReallyLongCondition || moreInThisLongCondition) ? null : (
+
+ )}
+ {isACat() &&
+ (someReallyLongCondition ||
+ moreInThisLongCondition ||
+ evenMoreInThisExtraLongConditional) ? null : (
+
+ )}
+
+);
+
+================================================================================
+`;
+
+exports[`new-ternary-spec.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+// from https://gist.github.com/rattrayalex/dacbf5838571a47f22d0ae1f8b960268
+// Input and output should match (for 2-space indent formatting).
+// TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts
+
+// remain on one line if possible:
+const short = isLoud() ? makeNoise() : silent();
+
+// next, put everything after the =
+const lessShort =
+ isLoudReallyLoud() ? makeNoiseReallyLoudly.omgSoLoud() : silent();
+
+// next, indent the consequent:
+const andIndented = isLoudReallyReallyReallyReallyLoud() ?
+ makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud()
+ : silent();
+
+// unless the consequent is short (less than ten characters long):
+const shortSoCase = isLoudReallyReallyReallyReallyLoud() ? silent()
+ : makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud();
+
+// if chained, always break and put after the =
+const chainedShort =
+ isCat() ? meow()
+ : isDog() ? bark()
+ : silent();
+
+// when a consequent breaks in a chain:
+const chainedWithLongConsequent =
+ isCat() ?
+ someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : isDog() ? bark()
+ : silent();
+
+// nested ternary in consequent always breaks:
+const chainedWithTernaryConsequent =
+ isCat() ?
+ aNestedCondition ? theResult()
+ : theAlternate()
+ : isDog() ? bark()
+ : silent();
+
+// consequent and terminal alternate break:
+const consequentAndTerminalAlternateBreak =
+ isCat() ?
+ someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : isDog() ? bark()
+ : someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens();
+
+// multiline conditions and consequents/alternates:
+const multilineConditionsConsequentsAndAlternates =
+ (
+ isAnAdorableKittyCat() &&
+ (someReallyLongCondition || moreInThisLongCondition)
+ ) ?
+ someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : (
+ isNotAnAdorableKittyCat() &&
+ (someReallyLongCondition || moreInThisLongCondition)
+ ) ?
+ bark()
+ : shortCondition() ? shortConsequent()
+ : someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens();
+
+// illustrating case of mostly short conditionals
+const mostlyShort =
+ x === 1 ? "one"
+ : x === 2 ? "two"
+ : x === 3 ? "three"
+ : (
+ x === 5 &&
+ y === 7 &&
+ someOtherThing.thatIsSoLong.thatItBreaksTheTestCondition()
+ ) ?
+ "four"
+ : x === 6 ? "six"
+ : "idk";
+
+// long conditional, short consequent/alternate, not chained - do indent after ?
+const longConditional = (
+ bifornCringerMoshedPerplexSawder === 2 / askTrovenaBeenaDependsRowans &&
+ glimseGlyphsHazardNoopsTieTie >=
+ averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol()
+ ) ?
+ "foo"
+ : "bar";
+
+// long conditional, short consequent/alternate, chained
+// (break on short consequents iff in chained ternary and its conditional broke)
+const longConditionalChained =
+ (
+ bifornCringerMoshedPerplexSawder === 2 / askTrovenaBeenaDependsRowans &&
+ glimseGlyphsHazardNoopsTieTie >=
+ averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol()
+ ) ?
+ "foo"
+ : anotherCondition ? "bar"
+ : "baz";
+
+// As a function parameter, don't add an extra indent:
+definition.encode(
+ typeof row[field] !== "undefined" ? row[field]
+ : typeof definition.default !== "undefined" ? definition.default
+ : null,
+ typeof row[field] === "undefined" ?
+ typeof definition.default === "undefined" ? null
+ : definition.default
+ : row[field]
+);
+
+// In a return, break and over-indent:
+const inReturn = () => {
+ if (short) {
+ return foo ? 1 : 2;
+ }
+ return typeof row[aVeryLongFieldName] !== "undefined" ?
+ row[aVeryLongFieldName]
+ : null;
+};
+
+// Remove current JSX Mode, and replace it with this algorithm:
+// When a ternary's parent is a JSXExpressionContainer which is not in a JSXAttribute,
+// force the consequent to break,
+// and if the alternate breaks,
+// add a newline before the closing curly brace.
+// Special case when the consequent is \`null\`:
+// do not add a line before or after it,
+// and wrap the alternate in parens.
+
+const someJSX = (
+
+ Typical jsx case:
+ {showFoo ?
+
+ :
}
+ Nested, and with a non-jsx consequent is the same:
+ {component ?
+ React.createElement(component, props)
+ : render ?
+
{render(props)}
+ :
Nothing is here
}
+ As is a non-jsx consequent:
+ {showTheJSXElement ?
+
the stuff
+ : renderOtherStuff()}
+ But if the alternate breaks, add a newline before the closing curly brace:
+ {showTheThing || pleaseShowTheThing ?
+
+ :
+ }
+ When the consequent is \`null\` and the alternate breaks,
+ hug it with parens to match boolean behavior:
+ {!thing ? null : (
+
+ )}
+
+);
+
+ternaryWithJSXElements.hasNoSpecialCasing =
+ component ? {React.createElement(component, props)}
+ : render ? {render(props)}
+ : Nothing is here
;
+
+jsxExpressionContainer.inJSXAttribute.hasNoSpecialCasing = (
+ : }
+ withJSXBroken={
+ isRed || isSomeOtherLongCondition.thatBreaksTheLine() ?
+
+ :
+ }
+ />
+);
+
+=====================================output=====================================
+// from https://gist.github.com/rattrayalex/dacbf5838571a47f22d0ae1f8b960268
+// Input and output should match (for 2-space indent formatting).
+// TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts
+
+// remain on one line if possible:
+const short = isLoud() ? makeNoise() : silent();
+
+// next, put everything after the =
+const lessShort = isLoudReallyLoud()
+ ? makeNoiseReallyLoudly.omgSoLoud()
+ : silent();
+
+// next, indent the consequent:
+const andIndented = isLoudReallyReallyReallyReallyLoud()
+ ? makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud()
+ : silent();
+
+// unless the consequent is short (less than ten characters long):
+const shortSoCase = isLoudReallyReallyReallyReallyLoud()
+ ? silent()
+ : makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud();
+
+// if chained, always break and put after the =
+const chainedShort = isCat() ? meow() : isDog() ? bark() : silent();
+
+// when a consequent breaks in a chain:
+const chainedWithLongConsequent = isCat()
+ ? someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : isDog()
+ ? bark()
+ : silent();
+
+// nested ternary in consequent always breaks:
+const chainedWithTernaryConsequent = isCat()
+ ? aNestedCondition
+ ? theResult()
+ : theAlternate()
+ : isDog()
+ ? bark()
+ : silent();
+
+// consequent and terminal alternate break:
+const consequentAndTerminalAlternateBreak = isCat()
+ ? someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : isDog()
+ ? bark()
+ : someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens();
+
+// multiline conditions and consequents/alternates:
+const multilineConditionsConsequentsAndAlternates =
+ isAnAdorableKittyCat() && (someReallyLongCondition || moreInThisLongCondition)
+ ? someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : isNotAnAdorableKittyCat() &&
+ (someReallyLongCondition || moreInThisLongCondition)
+ ? bark()
+ : shortCondition()
+ ? shortConsequent()
+ : someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens();
+
+// illustrating case of mostly short conditionals
+const mostlyShort =
+ x === 1
+ ? "one"
+ : x === 2
+ ? "two"
+ : x === 3
+ ? "three"
+ : x === 5 &&
+ y === 7 &&
+ someOtherThing.thatIsSoLong.thatItBreaksTheTestCondition()
+ ? "four"
+ : x === 6
+ ? "six"
+ : "idk";
+
+// long conditional, short consequent/alternate, not chained - do indent after ?
+const longConditional =
+ bifornCringerMoshedPerplexSawder === 2 / askTrovenaBeenaDependsRowans &&
+ glimseGlyphsHazardNoopsTieTie >=
+ averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol()
+ ? "foo"
+ : "bar";
+
+// long conditional, short consequent/alternate, chained
+// (break on short consequents iff in chained ternary and its conditional broke)
+const longConditionalChained =
+ bifornCringerMoshedPerplexSawder === 2 / askTrovenaBeenaDependsRowans &&
+ glimseGlyphsHazardNoopsTieTie >=
+ averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol()
+ ? "foo"
+ : anotherCondition
+ ? "bar"
+ : "baz";
+
+// As a function parameter, don't add an extra indent:
+definition.encode(
+ typeof row[field] !== "undefined"
+ ? row[field]
+ : typeof definition.default !== "undefined"
+ ? definition.default
+ : null,
+ typeof row[field] === "undefined"
+ ? typeof definition.default === "undefined"
+ ? null
+ : definition.default
+ : row[field]
+);
+
+// In a return, break and over-indent:
+const inReturn = () => {
+ if (short) {
+ return foo ? 1 : 2;
+ }
+ return typeof row[aVeryLongFieldName] !== "undefined"
+ ? row[aVeryLongFieldName]
+ : null;
+};
+
+// Remove current JSX Mode, and replace it with this algorithm:
+// When a ternary's parent is a JSXExpressionContainer which is not in a JSXAttribute,
+// force the consequent to break,
+// and if the alternate breaks,
+// add a newline before the closing curly brace.
+// Special case when the consequent is \`null\`:
+// do not add a line before or after it,
+// and wrap the alternate in parens.
+
+const someJSX = (
+
+ Typical jsx case:
+ {showFoo ?
:
}
+ Nested, and with a non-jsx consequent is the same:
+ {component ? (
+ React.createElement(component, props)
+ ) : render ? (
+
{render(props)}
+ ) : (
+
Nothing is here
+ )}
+ As is a non-jsx consequent:
+ {showTheJSXElement ?
the stuff
: renderOtherStuff()}
+ But if the alternate breaks, add a newline before the closing curly brace:
+ {showTheThing || pleaseShowTheThing ? (
+
+ ) : (
+
+ )}
+ When the consequent is \`null\` and the alternate breaks, hug it with parens
+ to match boolean behavior:
+ {!thing ? null : (
+
+ )}
+
+);
+
+ternaryWithJSXElements.hasNoSpecialCasing = component ? (
+ {React.createElement(component, props)}
+) : render ? (
+ {render(props)}
+) : (
+ Nothing is here
+);
+
+jsxExpressionContainer.inJSXAttribute.hasNoSpecialCasing = (
+ : }
+ withJSXBroken={
+ isRed || isSomeOtherLongCondition.thatBreaksTheLine() ? (
+
+ ) : (
+
+ )
+ }
+ />
+);
+
+================================================================================
+`;
+
exports[`no-confusing-arrow.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
@@ -256,3 +984,301 @@ var x = a <= 1 ? 2 : 3;
================================================================================
`;
+
+exports[`postfix-ternary-regressions.js format 1`] = `
+====================================options=====================================
+parsers: ["babel", "flow", "typescript"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+
+// concatened string in consequent should be visually distinguishable from alternate
+// … or maybe this is okay, because the colon is enough?
+const avatar = has_ordered ?
+ 'https://marmelab.com/posters/avatar/longer-word-that-breaks-consequent-' +
+ numberOfCustomers +
+ '.jpeg'
+ : undefined;
+
+// Similarly, in the alternate:
+const redirectUrl = pathName ?
+ pathName
+ : nextPathName + nextSearch ||
+ defaultAuthParams.afterLoginUrl.makeThisLongerSoItBreaks;
+
+// And another, more pathological case of the above:
+const isEmpty = obj =>
+ obj instanceof Date ?
+ false
+ : obj === '' ||
+ obj === null ||
+ obj === undefined ||
+ obj === somethingThatIsLonger ||
+ shallowEqual(obj, {});
+
+
+// Again, this case is a bit hard to distinguish the alternate.
+const eventsFromOrders =
+ orderIds && orders ?
+ orderIds.map(id => ({
+ type: 'order',
+ date: orders[id].date,
+ data: orders[id],
+ }))
+ : [];
+
+// Kinda weird to have dedents to the level of "return" in a function.
+function foo() {
+ return !linkTo ?
+ false
+ : typeof linkTo === 'function'
+ ? linkTo(record, reference)
+ : linkToRecord(rootPath, sourceId, linkTo_as_string);
+}
+function foo2() {
+ return React.isValidElement(emptyText)
+ ? React.cloneElement(emptyText)
+ : emptyText === ''
+ ? ' ' // em space, forces the display of an empty line of normal height
+ : translate(emptyText, { _: emptyText });
+}
+
+// Function call ideally wouldnt break break
+const matchingReferencesError = isMatchingReferencesError(
+ matchingReferences
+)
+ ? translate(matchingReferences.error, {
+ _: matchingReferences.error,
+ })
+ : null;
+
+// This one is kinda confusing any way you slice it…
+const obj = {
+ error:
+ matchingReferencesError &&
+ (!input.value ||
+ (input.value &&
+ selectedReferencesDataStatus === REFERENCES_STATUS_EMPTY))
+ ? translate('ra.input.references.all_missing', {
+ _: 'ra.input.references.all_missing',
+ })
+ : null,
+}
+
+// I think we should indent after the inner || on this, and do better wtih the parens around the &&
+const obj2 = {
+ warning:
+ matchingReferencesError ||
+ (input.value && selectedReferencesDataStatus !== REFERENCES_STATUS_READY)
+ ? matchingReferencesError ||
+ translate('ra.input.references.many_missing', {
+ _: 'ra.input.references.many_missing',
+ })
+ : null,
+}
+
+// The boolean conditions in the test should look cohesive.
+const selectedReferencesDataStatus =
+ !isEmpty(value) && typeof value === 'string' && !pattern.test(value)
+ ? getMessage(message, { pattern }, value, values)
+ : undefined
+
+
+// Would be nice if these two nested ternaries didn't look like a single one.
+resolveRedirectTo(
+ redirectTo,
+ basePath,
+ payload
+ ? payload.id || (payload.data ? payload.data.id : null)
+ : requestPayload
+ ? requestPayload.id
+ : null,
+ payload && payload.data
+ ? payload.data
+ : requestPayload && requestPayload.data
+ ? requestPayload.data
+ : null
+)
+
+const delayedDataProvider = new Proxy(restProvider, {
+ get: (target, name, self) =>
+ name === 'then' ? // as we await for the dataProvider, JS calls then on it. We must trap that call or else the dataProvider will be called with the then method
+ self
+ : (
+ (resource, params) =>
+ new Promise(resolve =>
+ setTimeout(
+ () =>
+ resolve(
+ restProvider[name](resource, params)
+ ),
+ 500
+ )
+ )
+ ),
+});
+
+function foo4() {
+ return !match || match.length < 5 ? line : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
+
+function foo5() {
+ return !match || match.length < 5 ? foo(line) : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
+
+function foo6() {
+ return !match || match.length < 5 ? linethatisverylongandbreaksthelinehooray : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
+
+function foo7() {
+ return !match || match.length < 5 ? linethatisverylongandbreaksthelinehoorayjustabitlonger : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
+
+=====================================output=====================================
+// concatened string in consequent should be visually distinguishable from alternate
+// … or maybe this is okay, because the colon is enough?
+const avatar = has_ordered
+ ? "https://marmelab.com/posters/avatar/longer-word-that-breaks-consequent-" +
+ numberOfCustomers +
+ ".jpeg"
+ : undefined;
+
+// Similarly, in the alternate:
+const redirectUrl = pathName
+ ? pathName
+ : nextPathName + nextSearch ||
+ defaultAuthParams.afterLoginUrl.makeThisLongerSoItBreaks;
+
+// And another, more pathological case of the above:
+const isEmpty = (obj) =>
+ obj instanceof Date
+ ? false
+ : obj === "" ||
+ obj === null ||
+ obj === undefined ||
+ obj === somethingThatIsLonger ||
+ shallowEqual(obj, {});
+
+// Again, this case is a bit hard to distinguish the alternate.
+const eventsFromOrders =
+ orderIds && orders
+ ? orderIds.map((id) => ({
+ type: "order",
+ date: orders[id].date,
+ data: orders[id],
+ }))
+ : [];
+
+// Kinda weird to have dedents to the level of "return" in a function.
+function foo() {
+ return !linkTo
+ ? false
+ : typeof linkTo === "function"
+ ? linkTo(record, reference)
+ : linkToRecord(rootPath, sourceId, linkTo_as_string);
+}
+function foo2() {
+ return React.isValidElement(emptyText)
+ ? React.cloneElement(emptyText)
+ : emptyText === ""
+ ? " " // em space, forces the display of an empty line of normal height
+ : translate(emptyText, { _: emptyText });
+}
+
+// Function call ideally wouldnt break break
+const matchingReferencesError = isMatchingReferencesError(matchingReferences)
+ ? translate(matchingReferences.error, {
+ _: matchingReferences.error,
+ })
+ : null;
+
+// This one is kinda confusing any way you slice it…
+const obj = {
+ error:
+ matchingReferencesError &&
+ (!input.value ||
+ (input.value && selectedReferencesDataStatus === REFERENCES_STATUS_EMPTY))
+ ? translate("ra.input.references.all_missing", {
+ _: "ra.input.references.all_missing",
+ })
+ : null,
+};
+
+// I think we should indent after the inner || on this, and do better wtih the parens around the &&
+const obj2 = {
+ warning:
+ matchingReferencesError ||
+ (input.value && selectedReferencesDataStatus !== REFERENCES_STATUS_READY)
+ ? matchingReferencesError ||
+ translate("ra.input.references.many_missing", {
+ _: "ra.input.references.many_missing",
+ })
+ : null,
+};
+
+// The boolean conditions in the test should look cohesive.
+const selectedReferencesDataStatus =
+ !isEmpty(value) && typeof value === "string" && !pattern.test(value)
+ ? getMessage(message, { pattern }, value, values)
+ : undefined;
+
+// Would be nice if these two nested ternaries didn't look like a single one.
+resolveRedirectTo(
+ redirectTo,
+ basePath,
+ payload
+ ? payload.id || (payload.data ? payload.data.id : null)
+ : requestPayload
+ ? requestPayload.id
+ : null,
+ payload && payload.data
+ ? payload.data
+ : requestPayload && requestPayload.data
+ ? requestPayload.data
+ : null
+);
+
+const delayedDataProvider = new Proxy(restProvider, {
+ get: (target, name, self) =>
+ name === "then" // as we await for the dataProvider, JS calls then on it. We must trap that call or else the dataProvider will be called with the then method
+ ? self
+ : (resource, params) =>
+ new Promise((resolve) =>
+ setTimeout(() => resolve(restProvider[name](resource, params)), 500)
+ ),
+});
+
+function foo4() {
+ return !match || match.length < 5
+ ? line
+ : match[1] + match[2] + match[3] + match[4];
+}
+
+function foo5() {
+ return !match || match.length < 5
+ ? foo(line)
+ : match[1] + match[2] + match[3] + match[4];
+}
+
+function foo6() {
+ return !match || match.length < 5
+ ? linethatisverylongandbreaksthelinehooray
+ : match[1] + match[2] + match[3] + match[4];
+}
+
+function foo7() {
+ return !match || match.length < 5
+ ? linethatisverylongandbreaksthelinehoorayjustabitlonger
+ : match[1] + match[2] + match[3] + match[4];
+}
+
+================================================================================
+`;
diff --git a/tests/format/js/conditional/comments.js b/tests/format/js/conditional/comments.js
index 84d735742..d6cdc984d 100644
--- a/tests/format/js/conditional/comments.js
+++ b/tests/format/js/conditional/comments.js
@@ -86,6 +86,7 @@ test
comment
comment
comment
+ A newline will be added after this comment, unfortunately – but it can be removed manually, see next statement.
*/
test
? foo
@@ -95,6 +96,23 @@ test
*/
bar;
+
+// It is at least possible to delete the extra newline that was
+// unfortunately added before the second condition above:
+test ?
+ foo :/* comment
+ comment
+ comment
+ comment
+ */
+test ?
+ foo :
+ /* comment
+ comment
+ comment
+ */
+ bar;
+
test
? foo
: /* comment */
diff --git a/tests/format/js/conditional/new-ternary-examples.js b/tests/format/js/conditional/new-ternary-examples.js
new file mode 100644
index 000000000..8c319faf9
--- /dev/null
+++ b/tests/format/js/conditional/new-ternary-examples.js
@@ -0,0 +1,138 @@
+// from https://gist.github.com/rattrayalex/dacbf5838571a47f22d0ae1f8b960268
+// Input and output should match (for 2-space indent formatting).
+// TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts
+// EXAMPLES
+// mostly taken from https://github.com/prettier/prettier/issues/9561
+
+const message =
+ i % 3 === 0 && i % 5 === 0 ? "fizzbuzz"
+ : i % 3 === 0 ? "fizz"
+ : i % 5 === 0 ? "buzz"
+ : String(i);
+
+const paymentMessageShort =
+ state == "success" ? "Payment completed successfully"
+ : state == "processing" ? "Payment processing"
+ : state == "invalid_cvc" ? "There was an issue with your CVC number"
+ : state == "invalid_expiry" ? "Expiry must be sometime in the past."
+ : "There was an issue with the payment. Please contact support.";
+
+const paymentMessageWithABreak =
+ state == "success" ? "Payment completed successfully"
+ : state == "processing" ? "Payment processing"
+ : state == "invalid_cvc" ?
+ "There was an issue with your CVC number, and you need to take a prompt action on it."
+ : state == "invalid_expiry" ? "Expiry must be sometime in the past."
+ : "There was an issue with the payment. Please contact support.";
+
+const typeofExample =
+ definition.encode ?
+ definition.encode(
+ typeof row[field] !== "undefined" ? row[field]
+ : typeof definition.default !== "undefined" ? definition.default
+ : null
+ )
+ : typeof row[field] !== "undefined" ? row[field]
+ : typeof definition.default !== "undefined" ? definition.default
+ : null
+
+// (the following is semantically equivalent to the above, but written in a more-confusing style – it'd be hard to grok no matter the formatting)
+const typeofExampleFlipped =
+ definition.encode ?
+ definition.encode(
+ typeof row[field] === "undefined" ?
+ typeof definition.default === "undefined" ? null
+ : definition.default
+ : row[field]
+ )
+ : typeof row[field] === "undefined" ?
+ typeof definition.default === "undefined" ? null
+ : definition.default
+ : row[field];
+
+
+// JSX Examples:
+
+const typicalLongConsequentWithNullAlternate = (
+
+ {children && !isEmptyChildren(children) ?
+
+ : null}
+
+);
+
+const reactRouterExampleJSX = (
+
+ {children && !isEmptyChildren(children) ?
+ children
+ : props.match ?
+ component ? React.createElement(component, props)
+ : render ? render(props)
+ : null
+ : null}
+
+);
+
+const reactRouterExampleNonJSX =
+ children && !isEmptyChildren(children) ? children
+ : props.match ?
+ component ? React.createElement(component, props)
+ : render ? render(props)
+ : null
+ : null;
+
+inJSXExpressionContainer.withLongConditionals.example = (
+
+ {(
+ isACat() &&
+ (someReallyLongCondition ||
+ moreInThisLongCondition)
+ ) ?
+ someReallyLargeExpression
+ .toMakeMeowNoise()
+ .willCauseParens()
+ : (
+ someReallyLongCondition ||
+ moreInThisLongCondition
+ ) ?
+ bark()
+ : someReallyLargeExpression
+ .toMakeMeowNoise()
+ .willCauseParens()
+ }
+
+);
+
+inJSXExpressionContainer.withLoops.orBooleans.example = (
+
+ {items ?
+ items.map((item) => (
+ item.display ?
+
+ :
+ ))
+ : null}
+
+ {showTheStuff && (
+ foo ?
+
+ :
+ )}
+
+);
+
+inJSXExpressionContainer.withNullConditional = (
+
+ {isACat() ? null : }
+ {isACat() && (someReallyLongCondition || moreInThisLongCondition) ? null : (
+
+ )}
+ {isACat() && (someReallyLongCondition || moreInThisLongCondition || evenMoreInThisExtraLongConditional) ? null : (
+
+ )}
+
+);
diff --git a/tests/format/js/conditional/new-ternary-spec.js b/tests/format/js/conditional/new-ternary-spec.js
new file mode 100644
index 000000000..74e7a362a
--- /dev/null
+++ b/tests/format/js/conditional/new-ternary-spec.js
@@ -0,0 +1,189 @@
+// from https://gist.github.com/rattrayalex/dacbf5838571a47f22d0ae1f8b960268
+// Input and output should match (for 2-space indent formatting).
+// TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts
+
+// remain on one line if possible:
+const short = isLoud() ? makeNoise() : silent();
+
+// next, put everything after the =
+const lessShort =
+ isLoudReallyLoud() ? makeNoiseReallyLoudly.omgSoLoud() : silent();
+
+// next, indent the consequent:
+const andIndented = isLoudReallyReallyReallyReallyLoud() ?
+ makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud()
+ : silent();
+
+// unless the consequent is short (less than ten characters long):
+const shortSoCase = isLoudReallyReallyReallyReallyLoud() ? silent()
+ : makeNoiseReallyReallyReallyReallyReallyLoudly.omgSoLoud();
+
+// if chained, always break and put after the =
+const chainedShort =
+ isCat() ? meow()
+ : isDog() ? bark()
+ : silent();
+
+// when a consequent breaks in a chain:
+const chainedWithLongConsequent =
+ isCat() ?
+ someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : isDog() ? bark()
+ : silent();
+
+// nested ternary in consequent always breaks:
+const chainedWithTernaryConsequent =
+ isCat() ?
+ aNestedCondition ? theResult()
+ : theAlternate()
+ : isDog() ? bark()
+ : silent();
+
+// consequent and terminal alternate break:
+const consequentAndTerminalAlternateBreak =
+ isCat() ?
+ someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : isDog() ? bark()
+ : someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens();
+
+// multiline conditions and consequents/alternates:
+const multilineConditionsConsequentsAndAlternates =
+ (
+ isAnAdorableKittyCat() &&
+ (someReallyLongCondition || moreInThisLongCondition)
+ ) ?
+ someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens()
+ : (
+ isNotAnAdorableKittyCat() &&
+ (someReallyLongCondition || moreInThisLongCondition)
+ ) ?
+ bark()
+ : shortCondition() ? shortConsequent()
+ : someReallyLargeExpression
+ .thatWouldCauseALineBreak()
+ .willCauseAnIndentButNotParens();
+
+// illustrating case of mostly short conditionals
+const mostlyShort =
+ x === 1 ? "one"
+ : x === 2 ? "two"
+ : x === 3 ? "three"
+ : (
+ x === 5 &&
+ y === 7 &&
+ someOtherThing.thatIsSoLong.thatItBreaksTheTestCondition()
+ ) ?
+ "four"
+ : x === 6 ? "six"
+ : "idk";
+
+// long conditional, short consequent/alternate, not chained - do indent after ?
+const longConditional = (
+ bifornCringerMoshedPerplexSawder === 2 / askTrovenaBeenaDependsRowans &&
+ glimseGlyphsHazardNoopsTieTie >=
+ averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol()
+ ) ?
+ "foo"
+ : "bar";
+
+// long conditional, short consequent/alternate, chained
+// (break on short consequents iff in chained ternary and its conditional broke)
+const longConditionalChained =
+ (
+ bifornCringerMoshedPerplexSawder === 2 / askTrovenaBeenaDependsRowans &&
+ glimseGlyphsHazardNoopsTieTie >=
+ averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol()
+ ) ?
+ "foo"
+ : anotherCondition ? "bar"
+ : "baz";
+
+// As a function parameter, don't add an extra indent:
+definition.encode(
+ typeof row[field] !== "undefined" ? row[field]
+ : typeof definition.default !== "undefined" ? definition.default
+ : null,
+ typeof row[field] === "undefined" ?
+ typeof definition.default === "undefined" ? null
+ : definition.default
+ : row[field]
+);
+
+// In a return, break and over-indent:
+const inReturn = () => {
+ if (short) {
+ return foo ? 1 : 2;
+ }
+ return typeof row[aVeryLongFieldName] !== "undefined" ?
+ row[aVeryLongFieldName]
+ : null;
+};
+
+// Remove current JSX Mode, and replace it with this algorithm:
+// When a ternary's parent is a JSXExpressionContainer which is not in a JSXAttribute,
+// force the consequent to break,
+// and if the alternate breaks,
+// add a newline before the closing curly brace.
+// Special case when the consequent is `null`:
+// do not add a line before or after it,
+// and wrap the alternate in parens.
+
+const someJSX = (
+
+ Typical jsx case:
+ {showFoo ?
+
+ :
}
+ Nested, and with a non-jsx consequent is the same:
+ {component ?
+ React.createElement(component, props)
+ : render ?
+
{render(props)}
+ :
Nothing is here
}
+ As is a non-jsx consequent:
+ {showTheJSXElement ?
+
the stuff
+ : renderOtherStuff()}
+ But if the alternate breaks, add a newline before the closing curly brace:
+ {showTheThing || pleaseShowTheThing ?
+
+ :
+ }
+ When the consequent is `null` and the alternate breaks,
+ hug it with parens to match boolean behavior:
+ {!thing ? null : (
+
+ )}
+
+);
+
+ternaryWithJSXElements.hasNoSpecialCasing =
+ component ? {React.createElement(component, props)}
+ : render ? {render(props)}
+ : Nothing is here
;
+
+jsxExpressionContainer.inJSXAttribute.hasNoSpecialCasing = (
+ : }
+ withJSXBroken={
+ isRed || isSomeOtherLongCondition.thatBreaksTheLine() ?
+
+ :
+ }
+ />
+);
diff --git a/tests/format/js/conditional/postfix-ternary-regressions.js b/tests/format/js/conditional/postfix-ternary-regressions.js
new file mode 100644
index 000000000..3d1f9ce7e
--- /dev/null
+++ b/tests/format/js/conditional/postfix-ternary-regressions.js
@@ -0,0 +1,150 @@
+
+// concatened string in consequent should be visually distinguishable from alternate
+// … or maybe this is okay, because the colon is enough?
+const avatar = has_ordered ?
+ 'https://marmelab.com/posters/avatar/longer-word-that-breaks-consequent-' +
+ numberOfCustomers +
+ '.jpeg'
+ : undefined;
+
+// Similarly, in the alternate:
+const redirectUrl = pathName ?
+ pathName
+ : nextPathName + nextSearch ||
+ defaultAuthParams.afterLoginUrl.makeThisLongerSoItBreaks;
+
+// And another, more pathological case of the above:
+const isEmpty = obj =>
+ obj instanceof Date ?
+ false
+ : obj === '' ||
+ obj === null ||
+ obj === undefined ||
+ obj === somethingThatIsLonger ||
+ shallowEqual(obj, {});
+
+
+// Again, this case is a bit hard to distinguish the alternate.
+const eventsFromOrders =
+ orderIds && orders ?
+ orderIds.map(id => ({
+ type: 'order',
+ date: orders[id].date,
+ data: orders[id],
+ }))
+ : [];
+
+// Kinda weird to have dedents to the level of "return" in a function.
+function foo() {
+ return !linkTo ?
+ false
+ : typeof linkTo === 'function'
+ ? linkTo(record, reference)
+ : linkToRecord(rootPath, sourceId, linkTo_as_string);
+}
+function foo2() {
+ return React.isValidElement(emptyText)
+ ? React.cloneElement(emptyText)
+ : emptyText === ''
+ ? ' ' // em space, forces the display of an empty line of normal height
+ : translate(emptyText, { _: emptyText });
+}
+
+// Function call ideally wouldnt break break
+const matchingReferencesError = isMatchingReferencesError(
+ matchingReferences
+)
+ ? translate(matchingReferences.error, {
+ _: matchingReferences.error,
+ })
+ : null;
+
+// This one is kinda confusing any way you slice it…
+const obj = {
+ error:
+ matchingReferencesError &&
+ (!input.value ||
+ (input.value &&
+ selectedReferencesDataStatus === REFERENCES_STATUS_EMPTY))
+ ? translate('ra.input.references.all_missing', {
+ _: 'ra.input.references.all_missing',
+ })
+ : null,
+}
+
+// I think we should indent after the inner || on this, and do better wtih the parens around the &&
+const obj2 = {
+ warning:
+ matchingReferencesError ||
+ (input.value && selectedReferencesDataStatus !== REFERENCES_STATUS_READY)
+ ? matchingReferencesError ||
+ translate('ra.input.references.many_missing', {
+ _: 'ra.input.references.many_missing',
+ })
+ : null,
+}
+
+// The boolean conditions in the test should look cohesive.
+const selectedReferencesDataStatus =
+ !isEmpty(value) && typeof value === 'string' && !pattern.test(value)
+ ? getMessage(message, { pattern }, value, values)
+ : undefined
+
+
+// Would be nice if these two nested ternaries didn't look like a single one.
+resolveRedirectTo(
+ redirectTo,
+ basePath,
+ payload
+ ? payload.id || (payload.data ? payload.data.id : null)
+ : requestPayload
+ ? requestPayload.id
+ : null,
+ payload && payload.data
+ ? payload.data
+ : requestPayload && requestPayload.data
+ ? requestPayload.data
+ : null
+)
+
+const delayedDataProvider = new Proxy(restProvider, {
+ get: (target, name, self) =>
+ name === 'then' ? // as we await for the dataProvider, JS calls then on it. We must trap that call or else the dataProvider will be called with the then method
+ self
+ : (
+ (resource, params) =>
+ new Promise(resolve =>
+ setTimeout(
+ () =>
+ resolve(
+ restProvider[name](resource, params)
+ ),
+ 500
+ )
+ )
+ ),
+});
+
+function foo4() {
+ return !match || match.length < 5 ? line : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
+
+function foo5() {
+ return !match || match.length < 5 ? foo(line) : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
+
+function foo6() {
+ return !match || match.length < 5 ? linethatisverylongandbreaksthelinehooray : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
+
+function foo7() {
+ return !match || match.length < 5 ? linethatisverylongandbreaksthelinehoorayjustabitlonger : (
+ match[1] + match[2] + match[3] + match[4]
+ )
+}
diff --git a/tests/format/js/ternaries/__snapshots__/jsfmt.spec.js.snap b/tests/format/js/ternaries/__snapshots__/jsfmt.spec.js.snap
index 64a356b85..3de99ae7a 100644
--- a/tests/format/js/ternaries/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/js/ternaries/__snapshots__/jsfmt.spec.js.snap
@@ -179,10 +179,11 @@ fn(
bifornCringerMoshedPerplexSawder,
askTrovenaBeenaDependsRowans,
glimseGlyphsHazardNoopsTieTie === averredBathersBoxroomBuggyNurl &&
- anodyneCondosMalateOverateRetinol
- ? annularCooeedSplicesWalksWayWay
- : kochabCooieGameOnOboleUnweave
+ anodyneCondosMalateOverateRetinol
+ ? annularCooeedSplicesWalksWayWay
+ : kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
=====================================output=====================================
fn(
@@ -193,6 +194,7 @@ fn(
? annularCooeedSplicesWalksWayWay
: kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
================================================================================
`;
@@ -209,10 +211,11 @@ fn(
bifornCringerMoshedPerplexSawder,
askTrovenaBeenaDependsRowans,
glimseGlyphsHazardNoopsTieTie === averredBathersBoxroomBuggyNurl &&
- anodyneCondosMalateOverateRetinol
- ? annularCooeedSplicesWalksWayWay
- : kochabCooieGameOnOboleUnweave
+ anodyneCondosMalateOverateRetinol
+ ? annularCooeedSplicesWalksWayWay
+ : kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
=====================================output=====================================
fn(
@@ -223,6 +226,7 @@ fn(
? annularCooeedSplicesWalksWayWay
: kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
================================================================================
`;
@@ -238,10 +242,11 @@ fn(
bifornCringerMoshedPerplexSawder,
askTrovenaBeenaDependsRowans,
glimseGlyphsHazardNoopsTieTie === averredBathersBoxroomBuggyNurl &&
- anodyneCondosMalateOverateRetinol
- ? annularCooeedSplicesWalksWayWay
- : kochabCooieGameOnOboleUnweave
+ anodyneCondosMalateOverateRetinol
+ ? annularCooeedSplicesWalksWayWay
+ : kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
=====================================output=====================================
fn(
@@ -252,6 +257,7 @@ fn(
? annularCooeedSplicesWalksWayWay
: kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
================================================================================
`;
@@ -266,10 +272,11 @@ fn(
bifornCringerMoshedPerplexSawder,
askTrovenaBeenaDependsRowans,
glimseGlyphsHazardNoopsTieTie === averredBathersBoxroomBuggyNurl &&
- anodyneCondosMalateOverateRetinol
- ? annularCooeedSplicesWalksWayWay
- : kochabCooieGameOnOboleUnweave
+ anodyneCondosMalateOverateRetinol
+ ? annularCooeedSplicesWalksWayWay
+ : kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
=====================================output=====================================
fn(
@@ -280,6 +287,7 @@ fn(
? annularCooeedSplicesWalksWayWay
: kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
================================================================================
`;
@@ -1816,6 +1824,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo));
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -2160,6 +2169,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo);
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -2468,6 +2478,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo));
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -2812,6 +2823,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo);
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -3119,6 +3131,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo));
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -3463,6 +3476,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo);
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -3769,6 +3783,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo));
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -4113,6 +4128,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo);
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
@@ -4315,6 +4331,34 @@ a
? line
: softline
+const config = {
+ onFailure: onFailure !== undefined ? onFailure : (
+ error => {
+ notify(
+ typeof error === 'string' ?
+ error
+ : error.message || 'ra.notification.http_error',
+ 'warning',
+ {
+ _:
+ typeof error === 'string' ? error
+ : error && error.message ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ }
+ )
+}
+
+showNotification(
+ typeof error === 'string' ? error : error.message || body,
+ level || 'warning',
+ {
+ messageArgs,
+ undoable: false,
+ }
+)
=====================================output=====================================
let icecream =
what == "cone"
@@ -4413,6 +4457,38 @@ a
? line
: softline;
+const config = {
+ onFailure:
+ onFailure !== undefined
+ ? onFailure
+ : (error) => {
+ notify(
+ typeof error === "string"
+ ? error
+ : error.message || "ra.notification.http_error",
+ "warning",
+ {
+ _:
+ typeof error === "string"
+ ? error
+ : error && error.message
+ ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ },
+};
+
+showNotification(
+ typeof error === "string" ? error : error.message || body,
+ level || "warning",
+ {
+ messageArgs,
+ undoable: false,
+ }
+);
+
================================================================================
`;
@@ -4520,6 +4596,34 @@ a
? line
: softline
+const config = {
+ onFailure: onFailure !== undefined ? onFailure : (
+ error => {
+ notify(
+ typeof error === 'string' ?
+ error
+ : error.message || 'ra.notification.http_error',
+ 'warning',
+ {
+ _:
+ typeof error === 'string' ? error
+ : error && error.message ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ }
+ )
+}
+
+showNotification(
+ typeof error === 'string' ? error : error.message || body,
+ level || 'warning',
+ {
+ messageArgs,
+ undoable: false,
+ }
+)
=====================================output=====================================
let icecream =
what == "cone"
@@ -4618,6 +4722,38 @@ a
? line
: softline;
+const config = {
+ onFailure:
+ onFailure !== undefined
+ ? onFailure
+ : (error) => {
+ notify(
+ typeof error === "string"
+ ? error
+ : error.message || "ra.notification.http_error",
+ "warning",
+ {
+ _:
+ typeof error === "string"
+ ? error
+ : error && error.message
+ ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ },
+};
+
+showNotification(
+ typeof error === "string" ? error : error.message || body,
+ level || "warning",
+ {
+ messageArgs,
+ undoable: false,
+ }
+);
+
================================================================================
`;
@@ -4724,6 +4860,34 @@ a
? line
: softline
+const config = {
+ onFailure: onFailure !== undefined ? onFailure : (
+ error => {
+ notify(
+ typeof error === 'string' ?
+ error
+ : error.message || 'ra.notification.http_error',
+ 'warning',
+ {
+ _:
+ typeof error === 'string' ? error
+ : error && error.message ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ }
+ )
+}
+
+showNotification(
+ typeof error === 'string' ? error : error.message || body,
+ level || 'warning',
+ {
+ messageArgs,
+ undoable: false,
+ }
+)
=====================================output=====================================
let icecream =
what == "cone"
@@ -4822,6 +4986,38 @@ a
? line
: softline;
+const config = {
+ onFailure:
+ onFailure !== undefined
+ ? onFailure
+ : (error) => {
+ notify(
+ typeof error === "string"
+ ? error
+ : error.message || "ra.notification.http_error",
+ "warning",
+ {
+ _:
+ typeof error === "string"
+ ? error
+ : error && error.message
+ ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ },
+};
+
+showNotification(
+ typeof error === "string" ? error : error.message || body,
+ level || "warning",
+ {
+ messageArgs,
+ undoable: false,
+ }
+);
+
================================================================================
`;
@@ -4927,6 +5123,34 @@ a
? line
: softline
+const config = {
+ onFailure: onFailure !== undefined ? onFailure : (
+ error => {
+ notify(
+ typeof error === 'string' ?
+ error
+ : error.message || 'ra.notification.http_error',
+ 'warning',
+ {
+ _:
+ typeof error === 'string' ? error
+ : error && error.message ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ }
+ )
+}
+
+showNotification(
+ typeof error === 'string' ? error : error.message || body,
+ level || 'warning',
+ {
+ messageArgs,
+ undoable: false,
+ }
+)
=====================================output=====================================
let icecream =
what == "cone"
@@ -5025,6 +5249,38 @@ a
? line
: softline;
+const config = {
+ onFailure:
+ onFailure !== undefined
+ ? onFailure
+ : (error) => {
+ notify(
+ typeof error === "string"
+ ? error
+ : error.message || "ra.notification.http_error",
+ "warning",
+ {
+ _:
+ typeof error === "string"
+ ? error
+ : error && error.message
+ ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ },
+};
+
+showNotification(
+ typeof error === "string" ? error : error.message || body,
+ level || "warning",
+ {
+ messageArgs,
+ undoable: false,
+ }
+);
+
================================================================================
`;
diff --git a/tests/format/js/ternaries/func-call.js b/tests/format/js/ternaries/func-call.js
index a87c7289e..527237c7c 100644
--- a/tests/format/js/ternaries/func-call.js
+++ b/tests/format/js/ternaries/func-call.js
@@ -2,7 +2,8 @@ fn(
bifornCringerMoshedPerplexSawder,
askTrovenaBeenaDependsRowans,
glimseGlyphsHazardNoopsTieTie === averredBathersBoxroomBuggyNurl &&
- anodyneCondosMalateOverateRetinol
- ? annularCooeedSplicesWalksWayWay
- : kochabCooieGameOnOboleUnweave
+ anodyneCondosMalateOverateRetinol
+ ? annularCooeedSplicesWalksWayWay
+ : kochabCooieGameOnOboleUnweave
);
+// TODO(rattrayalex): try to indent consequent/alternate here.
diff --git a/tests/format/js/ternaries/indent-after-paren.js b/tests/format/js/ternaries/indent-after-paren.js
index f4c0bdbf9..eacc4a6fa 100644
--- a/tests/format/js/ternaries/indent-after-paren.js
+++ b/tests/format/js/ternaries/indent-after-paren.js
@@ -199,6 +199,7 @@ bifornCringerMoshedPerplexSawder =
kochabCooieGameOnOboleUnweave === Math.PI
? averredBathersBoxroomBuggyNurl
: anodyneCondosMalateOverateRetinol)(Fooooooooooo.Fooooooooooo));
+// TODO(rattrayalex): try to fix this case
bifornCringerMoshedPerplexSawder = (
glimseGlyphsHazardNoopsTieTie === 0 &&
diff --git a/tests/format/js/ternaries/nested.js b/tests/format/js/ternaries/nested.js
index bfc1cba44..ce77c6750 100644
--- a/tests/format/js/ternaries/nested.js
+++ b/tests/format/js/ternaries/nested.js
@@ -93,3 +93,32 @@ a
}
? line
: softline
+
+const config = {
+ onFailure: onFailure !== undefined ? onFailure : (
+ error => {
+ notify(
+ typeof error === 'string' ?
+ error
+ : error.message || 'ra.notification.http_error',
+ 'warning',
+ {
+ _:
+ typeof error === 'string' ? error
+ : error && error.message ? error.message
+ : undefined,
+ }
+ );
+ refresh();
+ }
+ )
+}
+
+showNotification(
+ typeof error === 'string' ? error : error.message || body,
+ level || 'warning',
+ {
+ messageArgs,
+ undoable: false,
+ }
+)
\ No newline at end of file
diff --git a/tests/format/jsx/jsx/__snapshots__/jsfmt.spec.js.snap b/tests/format/jsx/jsx/__snapshots__/jsfmt.spec.js.snap
index e8776bdc0..a1dd16f69 100644
--- a/tests/format/jsx/jsx/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/jsx/jsx/__snapshots__/jsfmt.spec.js.snap
@@ -1102,6 +1102,13 @@ jsxModeFromElementBreaking ? (
{a ? "a" : b ? "b" : "c"}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo ? "a" : b ? "b" : "c"}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? "satellite" : isPublic ? "affairs" : network ? : "dun";
@@ -1243,6 +1250,17 @@ jsxModeFromElementBreaking ? (
// non-breaking.
{a ? "a" : b ? "b" : "c"}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo
+ ? "a"
+ : b
+ ? "b"
+ : "c"}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? "satellite" : isPublic ? "affairs" : network ? : "dun";
@@ -1401,6 +1419,13 @@ jsxModeFromElementBreaking ? (
{a ? "a" : b ? "b" : "c"}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo ? "a" : b ? "b" : "c"}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? "satellite" : isPublic ? "affairs" : network ? : "dun";
@@ -1542,6 +1567,17 @@ jsxModeFromElementBreaking ? (
// non-breaking.
{a ? "a" : b ? "b" : "c"}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo
+ ? "a"
+ : b
+ ? "b"
+ : "c"}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? "satellite" : isPublic ? "affairs" : network ? : "dun";
@@ -1700,6 +1736,13 @@ jsxModeFromElementBreaking ? (
{a ? "a" : b ? "b" : "c"}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo ? "a" : b ? "b" : "c"}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? "satellite" : isPublic ? "affairs" : network ? : "dun";
@@ -1841,6 +1884,17 @@ jsxModeFromElementBreaking ? (
// non-breaking.
{a ? 'a' : b ? 'b' : 'c'}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo
+ ? 'a'
+ : b
+ ? 'b'
+ : 'c'}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? 'satellite' : isPublic ? 'affairs' : network ? : 'dun';
@@ -1999,6 +2053,13 @@ jsxModeFromElementBreaking ? (
{a ? "a" : b ? "b" : "c"}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo ? "a" : b ? "b" : "c"}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? "satellite" : isPublic ? "affairs" : network ? : "dun";
@@ -2140,6 +2201,17 @@ jsxModeFromElementBreaking ? (
// non-breaking.
{a ? 'a' : b ? 'b' : 'c'}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo
+ ? 'a'
+ : b
+ ? 'b'
+ : 'c'}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? 'satellite' : isPublic ? 'affairs' : network ? : 'dun';
diff --git a/tests/format/jsx/jsx/conditional-expression.js b/tests/format/jsx/jsx/conditional-expression.js
index 3283d9c6a..703ce4d95 100644
--- a/tests/format/jsx/jsx/conditional-expression.js
+++ b/tests/format/jsx/jsx/conditional-expression.js
@@ -84,6 +84,13 @@ jsxModeFromElementBreaking ? (
{a ? "a" : b ? "b" : "c"}
;
+// This chain of ConditionalExpressions prints in JSX mode because the parent of
+// the outermost ConditionalExpression is a JSXExpressionContainer. It is
+// breaking.
+
+ {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo ? "a" : b ? "b" : "c"}
+
;
+
// This chain of ConditionalExpressions prints in JSX mode because there is a
// JSX element somewhere in the chain. It is non-breaking.
cable ? "satellite" : isPublic ? "affairs" : network ? : "dun";
diff --git a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap
index 7231c3da4..e598947c2 100644
--- a/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/typescript/conditional-types/__snapshots__/jsfmt.spec.js.snap
@@ -347,3 +347,87 @@ type Foo3 = (
================================================================================
`;
+
+exports[`new-ternary-spec.ts format 1`] = `
+====================================options=====================================
+parsers: ["typescript"]
+printWidth: 80
+ | printWidth
+=====================================input======================================
+// TypeScript has the same behavior, including a line break after =, but no parens around "conditional":
+type KnownKeys =
+ {
+ [K in keyof T]: string extends K ? never
+ : number extends K ? never
+ : K;
+ } extends { [_ in keyof T]: infer U } ?
+ {} extends U ? never
+ : U
+ : never;
+
+type KnownKeysWithLongExtends =
+ {
+ [K in keyof T]: string extends K ? never
+ : number extends K ? never
+ : K;
+ } extends {
+ [_ in keyof T]: SomeReallyLongThingThatBreaksTheLine
+ } ? U
+ : never;
+
+// TypeScript examples:
+type TypeName =
+ T extends string ? "string"
+ : T extends number ? "number"
+ : T extends boolean ? "boolean"
+ : T extends undefined ? "undefined"
+ : T extends Function ? "function"
+ : "object";
+
+type Unpacked =
+ T extends (infer U)[] ? U
+ : T extends (...args: any[]) => infer U ?
+ SomeReallyLongThingThatBreaksTheLine
+ : T extends Promise ? U
+ : T;
+=====================================output=====================================
+// TypeScript has the same behavior, including a line break after =, but no parens around "conditional":
+type KnownKeys = {
+ [K in keyof T]: string extends K ? never : number extends K ? never : K;
+} extends { [_ in keyof T]: infer U }
+ ? {} extends U
+ ? never
+ : U
+ : never;
+
+type KnownKeysWithLongExtends = {
+ [K in keyof T]: string extends K ? never : number extends K ? never : K;
+} extends {
+ [_ in keyof T]: SomeReallyLongThingThatBreaksTheLine;
+}
+ ? U
+ : never;
+
+// TypeScript examples:
+type TypeName = T extends string
+ ? "string"
+ : T extends number
+ ? "number"
+ : T extends boolean
+ ? "boolean"
+ : T extends undefined
+ ? "undefined"
+ : T extends Function
+ ? "function"
+ : "object";
+
+type Unpacked = T extends (infer U)[]
+ ? U
+ : T extends (...args: any[]) => infer U
+ ? SomeReallyLongThingThatBreaksTheLine
+ : T extends Promise
+ ? U
+ : T;
+
+================================================================================
+`;
diff --git a/tests/format/typescript/conditional-types/new-ternary-spec.ts b/tests/format/typescript/conditional-types/new-ternary-spec.ts
new file mode 100644
index 000000000..972d3e935
--- /dev/null
+++ b/tests/format/typescript/conditional-types/new-ternary-spec.ts
@@ -0,0 +1,36 @@
+// TypeScript has the same behavior, including a line break after =, but no parens around "conditional":
+type KnownKeys =
+ {
+ [K in keyof T]: string extends K ? never
+ : number extends K ? never
+ : K;
+ } extends { [_ in keyof T]: infer U } ?
+ {} extends U ? never
+ : U
+ : never;
+
+type KnownKeysWithLongExtends =
+ {
+ [K in keyof T]: string extends K ? never
+ : number extends K ? never
+ : K;
+ } extends {
+ [_ in keyof T]: SomeReallyLongThingThatBreaksTheLine
+ } ? U
+ : never;
+
+// TypeScript examples:
+type TypeName =
+ T extends string ? "string"
+ : T extends number ? "number"
+ : T extends boolean ? "boolean"
+ : T extends undefined ? "undefined"
+ : T extends Function ? "function"
+ : "object";
+
+type Unpacked =
+ T extends (infer U)[] ? U
+ : T extends (...args: any[]) => infer U ?
+ SomeReallyLongThingThatBreaksTheLine
+ : T extends Promise ? U
+ : T;
\ No newline at end of file