From 4b987eb9f9295fdf05ebdb1a2c85b1133c42bb51 Mon Sep 17 00:00:00 2001 From: Victorien Elvinger Date: Mon, 20 Nov 2023 00:46:56 +0100 Subject: [PATCH] chore(challenge): refine reports (#798) --- .../biome_formatter_test/src/diff_report.rs | 5 + crates/biome_js_formatter/report.md | 1923 ++++++++++++---- .../biome_js_formatter/report_incompatible.md | 1938 +++++++++++++---- .../assignment/issue-15534.js.prettier-snap | 15 +- .../js/assignment/issue-15534.js.snap | 68 + .../in_instanceof.js.prettier-snap | 86 +- .../binary-expressions/in_instanceof.js.snap | 293 +++ .../js/conditional/comments.js.prettier-snap | 20 +- .../prettier/js/conditional/comments.js.snap | 45 +- .../new-ternary-examples.js.prettier-snap | 80 +- .../conditional/new-ternary-examples.js.snap | 447 ++++ .../new-ternary-spec.js.prettier-snap | 58 +- .../js/conditional/new-ternary-spec.js.snap | 522 +++++ ...stfix-ternary-regressions.js.prettier-snap | 22 +- .../postfix-ternary-regressions.js.snap | 50 +- .../js/range/whitespace.js.prettier-snap | 1 + .../prettier/js/range/whitespace.js.snap | 28 + .../js/strings/escaped.js.prettier-snap | 5 +- .../specs/prettier/js/strings/escaped.js.snap | 7 +- .../js/ternaries/indent.js.prettier-snap | 8 +- .../prettier/js/ternaries/indent.js.snap | 357 +++ .../nested-in-condition.js.prettier-snap | 4 +- .../js/ternaries/nested-in-condition.js.snap | 112 + .../js/ternaries/nested.js.prettier-snap | 84 +- .../prettier/js/ternaries/nested.js.snap | 435 ++++ .../throw_expression.js.prettier-snap | 8 +- .../throw_expression.js.snap | 8 +- .../conditional-expression.js.prettier-snap | 4 +- .../jsx/jsx/conditional-expression.js.snap | 350 +++ .../as/expression-statement.ts.prettier-snap | 2 +- .../as/expression-statement.ts.snap | 2 +- .../ts-parameter-proerty.ts.prettier-snap | 6 +- .../comments/ts-parameter-proerty.ts.snap | 47 - .../comments.ts.prettier-snap | 14 +- .../conditional-types/comments.ts.snap | 198 ++ .../conditonal-types.ts.prettier-snap | 20 +- .../conditonal-types.ts.snap | 141 ++ .../infer-type.ts.prettier-snap | 8 +- .../conditional-types/infer-type.ts.snap | 57 + .../new-ternary-spec.ts.prettier-snap | 24 +- .../new-ternary-spec.ts.snap | 134 ++ .../conditional-types.ts.prettier-snap | 6 +- .../keyword-types/conditional-types.ts.snap | 58 + .../expression-statement.ts.prettier-snap | 16 +- .../expression-statement.ts.snap | 36 +- .../union/comments.ts.prettier-snap | 8 +- .../typescript/union/comments.ts.snap | 59 + .../union/consistent-with-flow/single-type.ts | 144 +- .../consistent-with-flow/single-type.ts.snap | 370 +--- 49 files changed, 6830 insertions(+), 1503 deletions(-) create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.snap delete mode 100644 crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap create mode 100644 crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap diff --git a/crates/biome_formatter_test/src/diff_report.rs b/crates/biome_formatter_test/src/diff_report.rs index 8bb6cdb25817..48f34628f141 100644 --- a/crates/biome_formatter_test/src/diff_report.rs +++ b/crates/biome_formatter_test/src/diff_report.rs @@ -131,13 +131,18 @@ impl DiffReport { "deferred-import-evaluation", // `import defer` syntax "source-phase-imports", // `import source` syntax "import-reflection", // `import module` syntax + "explicit-resource-management", // Embedded languages in template literals + "html-like", "js/multiparser", "js/range/issue-7082.js", "js/template-literals/css-prop.js", "js/template-literals/styled", "js/last-argument-expansion/embed.js", "typescript/as/as-const-embedded.ts", + "js/last-argument-expansion/embed.js", + "typescript/as/as-const-embedded.ts", + "styled-components", ]; patterns.iter().any(|pattern| file_name.contains(pattern)) diff --git a/crates/biome_js_formatter/report.md b/crates/biome_js_formatter/report.md index ab219ad84eba..4dabcdfe80e6 100644 --- a/crates/biome_js_formatter/report.md +++ b/crates/biome_js_formatter/report.md @@ -1,6 +1,6 @@ # Overall Metrics -**Average compatibility**: 95.63 +**Average compatibility**: 95.46
Definition @@ -8,7 +8,7 @@ $$average = \frac\{\sum_{file}^\{files}compatibility_\{file}}\{files}$$
- **Compatible lines**: 96.09 + **Compatible lines**: 95.52
Definition @@ -1089,8 +1089,28 @@ # js/assignment/issue-15534.js +```diff +-params["redirectTo"] = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params[ ++ "redirectTo" ++] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +-params["redirectTo"]["codePointAt"]["name"] = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params["redirectTo"]["codePointAt"][ ++ "name" ++] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +-params.redirectTo.bar.bar.ba.barab["foo"].abr = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params.redirectTo.bar.bar.ba.barab[ ++ "foo" ++].abr = `${window.location.pathname}${window.location.search}${window.location.hash}`; -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 18.18% # js/assignment/issue-1966.js @@ -1263,11 +1283,6 @@ **Prettier Similarity**: 100.00% -# js/babel-plugins/explicit-resource-management.js - -**Prettier Similarity**: 100.00% - - # js/babel-plugins/export-namespace-from.js **Prettier Similarity**: 100.00% @@ -1409,8 +1424,127 @@ # js/binary-expressions/in_instanceof.js - -**Prettier Similarity**: 100.00% +```diff +-(!foo) in bar; +-(!foo) in bar; ++!foo in bar; ++!foo in bar; + !(foo in bar); +-(!foo) in bar; ++!foo in bar; + +-(!foo) instanceof Bar; +-(!foo) instanceof Bar; ++!foo instanceof Bar; ++!foo instanceof Bar; + !(foo instanceof Bar); +-(!foo) instanceof Bar; ++!foo instanceof Bar; + +-(~foo) in bar; +-(~foo) in bar; ++~foo in bar; ++~foo in bar; + ~(foo in bar); +-(~foo) in bar; ++~foo in bar; + +-(~foo) instanceof Bar; +-(~foo) instanceof Bar; ++~foo instanceof Bar; ++~foo instanceof Bar; + ~(foo instanceof Bar); +-(~foo) instanceof Bar; ++~foo instanceof Bar; + +-(+foo) in bar; +-(+foo) in bar; +++foo in bar; +++foo in bar; + +(foo in bar); +-(+foo) in bar; +++foo in bar; + +-(+foo) instanceof Bar; +-(+foo) instanceof Bar; +++foo instanceof Bar; +++foo instanceof Bar; + +(foo instanceof Bar); +-(+foo) instanceof Bar; +++foo instanceof Bar; + +-(-foo) in bar; +-(-foo) in bar; ++-foo in bar; ++-foo in bar; + -(foo in bar); +-(-foo) in bar; ++-foo in bar; + +-(-foo) instanceof Bar; +-(-foo) instanceof Bar; ++-foo instanceof Bar; ++-foo instanceof Bar; + -(foo instanceof Bar); +-(-foo) instanceof Bar; ++-foo instanceof Bar; + +-(void 0) in bar; +-(void 0) in bar; ++void 0 in bar; ++void 0 in bar; + void (0 in bar); +-(void 0) in bar; ++void 0 in bar; + +-(void 0) instanceof bar; +-(void 0) instanceof bar; ++void 0 instanceof bar; ++void 0 instanceof bar; + void (0 instanceof bar); +-(void 0) instanceof bar; ++void 0 instanceof bar; + +-(delete 0) in bar; +-(delete 0) in bar; ++delete 0 in bar; ++delete 0 in bar; + delete (0 in bar); +-(delete 0) in bar; ++delete 0 in bar; + +-(delete 0) instanceof bar; +-(delete 0) instanceof bar; ++delete 0 instanceof bar; ++delete 0 instanceof bar; + delete (0 instanceof bar); +-(delete 0) instanceof bar; ++delete 0 instanceof bar; + +-(typeof 0) in bar; +-(typeof 0) in bar; ++typeof 0 in bar; ++typeof 0 in bar; + typeof (0 in bar); +-(typeof 0) in bar; ++typeof 0 in bar; + +-(typeof 0) instanceof bar; +-(typeof 0) instanceof bar; ++typeof 0 instanceof bar; ++typeof 0 instanceof bar; + typeof (0 instanceof bar); +-(typeof 0) instanceof bar; ++typeof 0 instanceof bar; + + ++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid + +-(!!foo) instanceof Bar; ++!!foo instanceof Bar; + +``` + +**Prettier Similarity**: 41.10% # js/binary-expressions/inline-jsx.js @@ -1811,30 +1945,6 @@ **Prettier Similarity**: 33.33% -# js/comments-closure-typecast/styled-components.js -```diff - const OverlapWrapper = - /** @type {import('styled-components').ThemedStyledFunction<'div',null,{overlap: boolean}>} */ - (styled.div)` -- position: relative; -+position:relative; - > { -- position: absolute; -- bottom: ${(p) => p.overlap === "previous" && 0}; -- top: ${(p) => p.overlap === "next" && 0}; -- } -- `; -+ position: absolute; -+ bottom: ${(p) => p.overlap === "previous" && 0}; -+top: ${(p) => p.overlap === "next" && 0}; -+} -+`; - -``` - -**Prettier Similarity**: 40.00% - - # js/comments-closure-typecast/superclass.js **Prettier Similarity**: 100.00% @@ -2081,18 +2191,6 @@ **Prettier Similarity**: 50.00% -# js/comments/html-like/comment.js -```diff - - -``` - -**Prettier Similarity**: 66.67% - - # js/comments/if.js **Prettier Similarity**: 100.00% @@ -2675,11 +2773,14 @@ */ foo : test - ? /* comment +- ? /* comment ++ ? /* comment comment comment */ - foo - : bar; +- foo +- : bar; ++ foo ++ : bar; test ? /* comment */ foo : bar; @@ -2700,13 +2801,17 @@ comment A newline will be added after this comment, unfortunately – but it can be removed manually, see next statement. */ - test - ? foo - : /* comment +- test +- ? foo +- : /* comment ++ test ++ ? foo ++ : /* comment comment comment */ - bar; +- bar; ++ bar; // It is at least possible to delete the extra newline that was // unfortunately added before the second condition above: @@ -2719,13 +2824,16 @@ comment */ - : test +- ? foo +- : /* comment + test - ? foo - : /* comment ++ ? foo ++ : /* comment comment comment */ - bar; +- bar; ++ bar; test ? foo : /* comment */ bar; @@ -2738,7 +2846,7 @@ ``` -**Prettier Similarity**: 97.56% +**Prettier Similarity**: 89.43% # js/conditional/new-expression.js @@ -2747,13 +2855,430 @@ # js/conditional/new-ternary-examples.js +```diff + // 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); ++ ? "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."; ++ ? "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."; ++ ? "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, ++ ? definition.default ++ : null, + ) + : typeof row[field] !== "undefined" +- ? row[field] +- : typeof definition.default !== "undefined" +- ? definition.default +- : null; ++ ? 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]; ++ ? 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} ++ ? 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; ++ ? 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()} ++ ? 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 : ( + + )} +
+ ); -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 73.33% # js/conditional/new-ternary-spec.js +```diff + // 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(); ++ ? bark() ++ : silent(); + + // nested ternary in consequent always breaks: + const chainedWithTernaryConsequent = isCat() + ? aNestedCondition + ? theResult() + : theAlternate() + : isDog() +- ? bark() +- : silent(); ++ ? bark() ++ : silent(); + + // consequent and terminal alternate break: + const consequentAndTerminalAlternateBreak = isCat() + ? someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : isDog() +- ? bark() +- : someReallyLargeExpression +- .thatWouldCauseALineBreak() +- .willCauseAnIndentButNotParens(); ++ ? 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(); ++ (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"; ++ ? "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"; ++ ? "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, ++ ? 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() ? ( + + ) : ( + + ) + } + /> + ); -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 84.90% # js/conditional/no-confusing-arrow.js @@ -2802,15 +3327,19 @@ return !linkTo ? false : typeof linkTo === "function" - ? linkTo(record, reference) - : linkToRecord(rootPath, sourceId, linkTo_as_string); +- ? linkTo(record, reference) +- : linkToRecord(rootPath, sourceId, linkTo_as_string); ++ ? 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 }); +- ? " " // em space, forces the display of an empty line of normal height +- : translate(emptyText, { _: emptyText }); ++ ? " " // em space, forces the display of an empty line of normal height ++ : translate(emptyText, { _: emptyText }); } // Function call ideally wouldnt break break @@ -2857,13 +3386,17 @@ payload ? payload.id || (payload.data ? payload.data.id : null) : requestPayload - ? requestPayload.id - : null, +- ? requestPayload.id +- : null, ++ ? requestPayload.id ++ : null, payload && payload.data ? payload.data : requestPayload && requestPayload.data - ? requestPayload.data - : null, +- ? requestPayload.data +- : null, ++ ? requestPayload.data ++ : null, ); const delayedDataProvider = new Proxy(restProvider, { @@ -2909,9 +3442,12 @@ const badComments = schema.model ? schema : // If model is an array where the items schema is a referred model then we need to use that - schema.type === "array" - ? schema.items - : schema; +- schema.type === "array" +- ? schema.items +- : schema; ++ schema.type === "array" ++ ? schema.items ++ : schema; const anotherBadComment = refModel ? // If we're in a shared params file then reference the model name directly @@ -2924,7 +3460,7 @@ ``` -**Prettier Similarity**: 98.08% +**Prettier Similarity**: 91.03% # js/cursor/comments-1.js @@ -3411,183 +3947,6 @@ **Prettier Similarity**: 100.00% -# js/explicit-resource-management/for-await-using-of-comments.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/invalid-duplicate-using-bindings.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/invalid-script-top-level-using-binding.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/using-declarations.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-expr-using-in.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-expr-using-instanceof.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-expr-using.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-using-asi-assignment.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-using-binding-basic.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-using-binding-escaped.js -```diff - async function f() { -- await using ab = c; -+ await using \u0061b = c; - } - -``` - -**Prettier Similarity**: 66.67% - - -# js/explicit-resource-management/valid-await-using-binding-non-bmp.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-using-binding-using.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-await-using-comments.js -```diff - async function f() { - { -- /*0*/ await using /*1*/ /*2*/ b /*3*/ = /*4*/ f(); /*5*/ -+ /*0*/ await using /*1*/ /*2*/ b /*3*/ = /*4*/ f() /*5*/; - } - { - /*0*/ for ( - /*1*/ /*2*/ await using /*3*/ /*4*/ b /*5*/ = - /*6*/ x /*7*/ /*8*/ /*9*/ /*10*/; - ; -- - ); - } - { - /*0*/ for (/*1*/ /*2*/ await using /*3*/ /*4*/ b /*5*/ of /*6*/ x /*7*/ /*8*/); - } - { - /*0*/ for await (/*1*/ /*2*/ /*3*/ await using /*4*/ /*5*/ b /*6*/ of /*7*/ x /*8*/ /*9*/); - } - } - -``` - -**Prettier Similarity**: 89.47% - - -# js/explicit-resource-management/valid-for-await-using-binding-escaped-of-of.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-for-using-binding-escaped-of-of.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-for-using-binding-of-of.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-for-using-declaration.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-as-identifier-computed-member.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-as-identifier-expression-statement.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-as-identifier-for-await-of.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-as-identifier-for-in.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-as-identifier-for-init.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-as-identifier-for-of.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-as-identifier-in.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-binding-basic.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-binding-escaped.js -```diff - { -- using ab = c; -+ using \u0061b = c; - } - -``` - -**Prettier Similarity**: 66.67% - - -# js/explicit-resource-management/valid-using-binding-non-bmp.js - -**Prettier Similarity**: 100.00% - - -# js/explicit-resource-management/valid-using-binding-using.js - -**Prettier Similarity**: 100.00% - - # js/export-default/binary_and_template.js **Prettier Similarity**: 100.00% @@ -5505,8 +5864,12 @@ # js/range/whitespace.js +```diff +- -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 0.00% # js/regex/d-flag.js @@ -5729,9 +6092,8 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = goog.getMsg("That's all we know"); --export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = goog.getMsg( -- "That's all we know", --); +-export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = +- goog.getMsg("That's all we know"); +// FIXME +// TODO: reformat issue +// export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = @@ -5943,18 +6305,404 @@ # js/ternaries/indent.js +```diff + aaaaaaaaaaaaaaa + ? bbbbbbbbbbbbbbbbbb + : ccccccccccccccc +- ? ddddddddddddddd +- : eeeeeeeeeeeeeee +- ? fffffffffffffff +- : gggggggggggggggg; ++ ? ddddddddddddddd ++ : eeeeeeeeeeeeeee ++ ? fffffffffffffff ++ : gggggggggggggggg; + + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; + + a + ? { + a: 0, + } + : { + a: { + a: 0, + } + ? { + a: 0, + } + : { + y: { + a: 0, + } + ? { + a: 0, + } + : { + a: 0, + }, + }, + }; + + a + ? { + a: function () { + return a + ? { + a: [ + a + ? { + a: 0, + b: [a ? [0, 1] : []], + } + : [ + [ + 0, + { + a: 0, + }, + a ? 0 : 1, + ], + function () { + return a + ? { + a: 0, + } + : [ + { + a: 0, + }, + {}, + ]; + }, + ], + ], + } + : [ + a + ? function () { + a + ? a( + a + ? { + a: a({ + a: 0, + }), + } + : [ + 0, + a(), + a( + a(), + { + a: 0, + }, + a + ? a() + : a({ + a: 0, + }), + ), + a() + ? { + a: a(), + b: [], + } + : {}, + ], + ) + : a( + a() + ? { + a: 0, + } + : (function (a) { + return a() + ? [ + { + a: 0, + b: a(), + }, + ] + : a([ + a + ? { + a: 0, + } + : {}, + { + a: 0, + }, + ]); + })( + a + ? function (a) { + return function () { + return 0; + }; + } + : function (a) { + return function () { + return 1; + }; + }, + ), + ); + } + : function () {}, + ]; + }, + } + : a; -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 97.33% # js/ternaries/nested-in-condition.js +```diff + $var = ( + $number % 10 >= 2 && ($number % 100 < 10 || $number % 100 >= 20) + ? kochabCooieGameOnOboleUnweave + : annularCooeedSplicesWalksWayWay + ) + ? anodyneCondosMalateOverateRetinol + : averredBathersBoxroomBuggyNurl; + + const value = ( + bifornCringerMoshedPerplexSawder + ? askTrovenaBeenaDependsRowans + : glimseGlyphsHazardNoopsTieTie + ) + ? true + ? true + : false + : true +- ? true +- : false; ++ ? true ++ : false; + + ( + bifornCringerMoshedPerplexSawder + ? askTrovenaBeenaDependsRowans + : glimseGlyphsHazardNoopsTieTie + ) ? ( + + + + + + + + + ) : ( + + + + + + ); -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 95.00% # js/ternaries/nested.js +```diff + let icecream = + what == "cone" + ? (p) => (!!p ? `here's your ${p} cone` : `just the empty cone for you`) + : (p) => `here's your ${p} ${what}`; + + const value = condition1 + ? value1 + : condition2 +- ? value2 +- : condition3 +- ? value3 +- : value4; ++ ? value2 ++ : condition3 ++ ? value3 ++ : value4; + + const StorybookLoader = ({ match }) => + match.params.storyId === "button" ? ( + + ) : match.params.storyId === "color" ? ( + + ) : match.params.storyId === "typography" ? ( + + ) : match.params.storyId === "loading" ? ( + + ) : match.params.storyId === "deal-list" ? ( + + ) : ( + + {"Missing story book"} + + + + + ); + + const message = + i % 3 === 0 && i % 5 === 0 + ? "fizzbuzz" + : i % 3 === 0 +- ? "fizz" +- : i % 5 === 0 +- ? "buzz" +- : String(i); ++ ? "fizz" ++ : i % 5 === 0 ++ ? "buzz" ++ : String(i); + + const paymentMessage = + 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."; ++ ? "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 paymentMessage2 = + state == "success" + ? 1 //'Payment completed successfully' + : state == "processing" +- ? 2 //'Payment processing' +- : state == "invalid_cvc" +- ? 3 //'There was an issue with your CVC number' +- : true //state == 'invalid_expiry' +- ? 4 //'Expiry must be sometime in the past.' +- : 5; // 'There was an issue with the payment. Please contact support.' ++ ? 2 //'Payment processing' ++ : state == "invalid_cvc" ++ ? 3 //'There was an issue with your CVC number' ++ : true //state == 'invalid_expiry' ++ ? 4 //'Expiry must be sometime in the past.' ++ : 5; // 'There was an issue with the payment. Please contact support.' + + const foo = ( +
+ {medals[0].record + ? i18n("Record") + : medals[0].unique +- ? i18n("Unique") +- : medals[0].type === 0 +- ? i18n("Silver") +- : medals[0].type === 1 +- ? i18n("Gold") +- : medals[0].type === 2 +- ? i18n("Platinum") +- : i18n("Theme")} ++ ? i18n("Unique") ++ : medals[0].type === 0 ++ ? i18n("Silver") ++ : medals[0].type === 1 ++ ? i18n("Gold") ++ : medals[0].type === 2 ++ ? i18n("Platinum") ++ : i18n("Theme")} +
+ ); + + a + ? literalline + : { +- 123: 12, +- } +- ? line +- : softline; ++ 123: 12, ++ } ++ ? 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, ++ ? error.message ++ : undefined, + }, + ); + refresh(); + }, + }; + + showNotification( + typeof error === "string" ? error : error.message || body, + level || "warning", + { + messageArgs, + undoable: false, + }, + ); + + const result = + children && !isEmptyChildren(children) + ? children + : props.match +- ? component +- ? React.createElement(component, props) +- : render +- ? render(props) +- : null +- : null; ++ ? component ++ ? React.createElement(component, props) ++ : render ++ ? render(props) ++ : null ++ : null; -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 69.78% # js/ternaries/parenthesis.js @@ -6656,8 +7404,174 @@ # jsx/jsx/conditional-expression.js +```diff + // There are two ways to print ConditionalExpressions: "normal mode" and + // "JSX mode". This is normal mode (when breaking): + // + // test + // ? consequent + // : alternate; + // + // And this is JSX mode (when breaking): + // + // test ? ( + // consequent + // ) : ( + // alternate + // ); + // + // When non-breaking, they look the same: + // + // test ? consequent : alternate; + // + // We only print a conditional expression in JSX mode if its test, + // consequent, or alternate are JSXElements. + // Otherwise, we print in normal mode. + + // This ConditionalExpression has no JSXElements so it prints in normal mode. + // The line does not break. + normalModeNonBreaking ? "a" : "b"; + + // This ConditionalExpression has no JSXElements so it prints in normal mode. + // Its consequent is very long, so it breaks out to multiple lines. + normalModeBreaking + ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa + : "c"; + + // This ConditionalExpression prints in JSX mode because its test is a + // JSXElement. It is non-breaking. + // Note: I have never, ever seen someone use a JSXElement as the test in a + // ConditionalExpression. But this test is included for completeness. +
? jsxModeFromElementNonBreaking : "a"; + + // This ConditionalExpression prints in JSX mode because its consequent is a + // JSXElement. It is non-breaking. + jsxModeFromElementNonBreaking ?
: "a"; + + // This ConditionalExpression prints in JSX mode because its alternate is a + // JSXElement. It is non-breaking. + jsxModeFromElementNonBreaking ? "a" :
; + + // This ConditionalExpression prints in JSX mode because its test is a + // JSXElement. It is breaking. + // Note: I have never, ever seen someone use a JSXElement as the test in a + // ConditionalExpression. But this test is included for completeness. +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
? ( + "jsx mode from element breaking" + ) : ( + "a" + ); + + // This ConditionalExpression prints in JSX mode because its consequent is a + // JSXElement. It is breaking. + jsxModeFromElementBreaking ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ) : ( + "a" + ); + + // This ConditionalExpression prints in JSX mode because its alternate is a + // JSXElement. It is breaking. + jsxModeFromElementBreaking ? ( + "a" + ) : ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ); + + // This chain of ConditionalExpressions prints in JSX mode because the parent of + // the outermost ConditionalExpression is a JSXExpressionContainer. It is + // 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"} ++ ? "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"; + + // This chain of ConditionalExpressions prints in JSX mode because there is a + // JSX element somewhere in the chain (in this case, at the end). It is + // breaking; notice the consequents and alternates in the entire chain get + // wrapped in parens. + cable ? ( + "satellite" + ) : isPublic ? ( + "affairs" + ) : network ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ) : ( + "dunno" + ); + + // This chain of ConditionalExpressions prints in JSX mode because there is a + // JSX element somewhere in the chain (in this case, at the beginning). It is + // breaking; notice the consequents and alternates in the entire chain get + // wrapped in parens. + cable ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ) : sateline ? ( + "public" + ) : affairs ? ( + "network" + ) : ( + "dunno" + ); + + // This chain of ConditionalExpressions prints in JSX mode because there is a + // JSX element somewhere in the chain. It is breaking; notice the consequents + // and alternates in the entire chain get wrapped in parens. +
+ {properties.length > 1 || + (properties.length === 1 && properties[0].apps.size > 1) ? ( + draggingApp == null || newPropertyName == null ? ( + + ) : ( + + ) + ) : null} +
; + + // #3552 + foo ? ( + + loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong jsx + + ) : undefined; -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 98.76% # jsx/jsx/expression.js @@ -6995,36 +7909,6 @@ **Prettier Similarity**: 100.00% -# jsx/template/styled-components.js -```diff - ; - - ; - - ; - -``` - -**Prettier Similarity**: 78.95% - - # jsx/text-wrap/test.js ```diff // Wrapping text @@ -7744,7 +8628,7 @@ ```diff // expression statemnt of "as" expression hardly ever makes sense, but it's still valid. const [type, x] = [0, 0]; --type as unknown; +-(type) as unknown; +// FIXME +// TODO: parse issue +// (type) as unknown; @@ -8297,19 +9181,8 @@ # typescript/comments/ts-parameter-proerty.ts -```diff - class A { -- constructor(private readonly paramProp: Type) // comment -- {} -+ constructor( -+ private readonly paramProp: Type, -+ // comment -+ ) {} - } - -``` -**Prettier Similarity**: 33.33% +**Prettier Similarity**: 100.00% # typescript/comments/type-parameters.ts @@ -8516,18 +9389,176 @@ # typescript/conditional-types/comments.ts +```diff + type A = B extends T + ? // comment + foo + : bar; + + type A = B extends test /* comment + comment + comment + */ + ? foo + : bar; + + type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : bar; + + type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : test extends B +- ? /* comment ++ ? /* comment + comment + comment */ +- foo +- : bar; ++ foo ++ : bar; + + type T = test extends B ? /* comment */ foo : bar; + + type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ + bar; + + type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ +- test extends B +- ? foo +- : /* comment ++ test extends B ++ ? foo ++ : /* comment + comment + comment + */ +- bar; ++ bar; + + type T = test extends B ? foo : /* comment */ bar; + + type T = test extends B + ? test extends B /* c + c */ + ? foo + : bar + : bar; -**Prettier Similarity**: 100.00% +``` +**Prettier Similarity**: 89.86% -# typescript/conditional-types/conditonal-types.ts -**Prettier Similarity**: 100.00% +# typescript/conditional-types/conditonal-types.ts +```diff + export type DeepReadonly = T extends any[] + ? DeepReadonlyArray + : T extends object +- ? DeepReadonlyObject +- : T; ++ ? DeepReadonlyObject ++ : T; + + type NonFunctionPropertyNames = { + [K in keyof T]: T[K] extends Function ? never : K; + }[keyof T]; + + interface DeepReadonlyArray extends ReadonlyArray> {} + + type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; + }; + + type TypeName = T extends string + ? "string" + : T extends number +- ? "number" +- : T extends boolean +- ? "boolean" +- : T extends undefined +- ? "undefined" +- : T extends Function +- ? "function" +- : "object"; ++ ? "number" ++ : T extends boolean ++ ? "boolean" ++ : T extends undefined ++ ? "undefined" ++ : T extends Function ++ ? "function" ++ : "object"; + + type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type02 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type03 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type04 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type05 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + type Type06 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + type Type07 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + type Type08 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + + type T1 = () => void extends T ? U : V; + type T1a = () => void extends T ? U : V; + type T1b = () => void extends T ? U : V; + type T2 = (() => void) extends T ? U : V; + + type U1 = new () => X extends T ? U : V; + type U1a = new () => X extends T ? U : V; + type U1b = new () => X extends T ? U : V; + type U2 = (new () => X) extends T ? U : V; + +``` + +**Prettier Similarity**: 78.26% # typescript/conditional-types/infer-type.ts +```diff + type TestReturnType any> = T extends ( + ...args: any[] + ) => infer R + ? R + : any; + + type Unpacked = T extends (infer U)[] + ? U + : T extends (...args: any[]) => infer U +- ? U +- : T extends Promise +- ? U +- : T; ++ ? U ++ : T extends Promise ++ ? U ++ : T; -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 69.23% # typescript/conditional-types/nested-in-condition.ts @@ -8536,8 +9567,60 @@ # typescript/conditional-types/new-ternary-spec.ts +```diff + // 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"; ++ ? "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; ++ ? SomeReallyLongThingThatBreaksTheLine ++ : T extends Promise ++ ? U ++ : T; -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 67.57% # typescript/conditional-types/parentheses.ts @@ -9501,13 +10584,8 @@ # typescript/conformance/types/moduleDeclaration/kind-detection.ts -```diff --declare namespace /* module */ A {} -+declare /* module */ namespace A {} -``` - -**Prettier Similarity**: 0.00% +**Prettier Similarity**: 100.00% # typescript/conformance/types/moduleDeclaration/moduleDeclaration.ts @@ -10303,15 +11381,14 @@ // note lack of trailing comma in the index signature type TooLongSingleParam = { -- [ -- looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: string -- ]: string; -+ [looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: string]: string; + [ + looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: string + ]: string; }; ``` -**Prettier Similarity**: 38.71% +**Prettier Similarity**: 48.39% # typescript/error-recovery/jsdoc_only_types.ts @@ -10344,16 +11421,6 @@ **Prettier Similarity**: 6.67% -# typescript/explicit-resource-management/await-using-with-type-declaration.ts - -**Prettier Similarity**: 100.00% - - -# typescript/explicit-resource-management/using-with-type-declaration.ts - -**Prettier Similarity**: 100.00% - - # typescript/export-default/function_as.ts **Prettier Similarity**: 100.00% @@ -10843,8 +11910,22 @@ # typescript/keyword-types/conditional-types.ts +```diff + export type UnwrappedResultRow = { + [P in keyof T]: T[P] extends Req + ? a + : T[P] extends Opt +- ? b +- : // TEST +- never; ++ ? b ++ : // TEST ++ never; + }; -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 62.50% # typescript/keyword-types/keyword-types-with-parens-comments.ts @@ -11609,22 +12690,21 @@ return 2; default: // exhaustiveness check idiom - type satisfies never; +- (type) satisfies never; ++ type satisfies never; throw new Error("unreachable"); } }; function needParens() { -- let satisfies unknown; -- interface satisfies unknown; -+ (let) satisfies unknown; -+ (interface) satisfies unknown; - module satisfies unknown; - using satisfies unknown; -- yield satisfies unknown; -- await satisfies unknown; -+ (yield) satisfies unknown; -+ (await) satisfies unknown; + (let) satisfies unknown; + (interface) satisfies unknown; +- (module) satisfies unknown; +- (using) satisfies unknown; ++ module satisfies unknown; ++ using satisfies unknown; + (yield) satisfies unknown; + (await) satisfies unknown; } function noNeedParens() { @@ -11637,7 +12717,8 @@ function satisfiesChain() { satisfies satisfies satisfies satisfies satisfies; - type satisfies never satisfies unknown; +- (type) satisfies never satisfies unknown; ++ type satisfies never satisfies unknown; } ``` @@ -12166,8 +13247,25 @@ # typescript/union/comments.ts +```diff + type Foo = ( + | "thing1" // Comment1 +- | "thing2" // Comment2 +-)[]; // Final comment1 ++ | "thing2" ++)[]; // Comment2 // Final comment1 + + type Foo = ( + | "thing1" // Comment1 +- | "thing2" // Comment2 +-) & ++ | "thing2" ++) & // Comment2 + Bar; // Final comment2 -**Prettier Similarity**: 100.00% +``` + +**Prettier Similarity**: 60.00% # typescript/union/consistent-with-flow/comment.ts @@ -12218,95 +13316,40 @@ # typescript/union/consistent-with-flow/single-type.ts ```diff --type A1 = -- | A -- // A comment to force break -- | B; --type A2 = -- | ( -- | A -- // A comment to force break -- | B -- ) -- | ( -- | A -- // A comment to force break -- | B -- ); --type A3 = -- | A -- // A comment to force break -- | B; --type A4 = -- | A -- // A comment to force break -- | B; --type A5 = -- | ({ key: string } | { key: string } | { key: string } | { key: string }) -- | { key: string } -- | { key: string }; + type A1 = + | A + // A comment to force break + | B; + type A2 = + | ( + | A + // A comment to force break + | B + ) + | ( + | A + // A comment to force break + | B + ); + type A3 = + | A + // A comment to force break + | B; + type A4 = + | A + // A comment to force break + | B; + type A5 = + | ({ key: string } | { key: string } | { key: string } | { key: string }) + | { key: string } + | { key: string }; -type A6 = - /*1*/ - | A - // A comment to force break - | B; -- --type B1 = -- | A -- // A comment to force break -- | B; --type B2 = -- | A -- // A comment to force break -- | B; +// FIXME -+// TODO: we emit invalid AST -+// type A1 = -+// | ( -+// | ( -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ); -+// type A2 = -+// | ( -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ); -+// type A3 = -+// | ( | ( -+// | A -+// // A comment to force break -+// | B -+// ) ); -+// type A4 = -+// | ( | ( | ( -+// | A -+// // A comment to force break -+// | B -+// ) ) ); -+// type A5 = -+// | ( -+// | ( -+// | { key: string } -+// | { key: string } -+// | { key: string } -+// | { key: string } -+// ) -+// | { key: string } -+// | { key: string } -+// ); ++// TODO: reformat issue +// type A6 = | ( +// /*1*/ | ( +// | ( @@ -12316,35 +13359,19 @@ +// ) +// ) +// ); -+// -+// type B1 = -+// | ( -+// & ( -+// ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ); -+// type B2 = -+// | ( -+// & ( -+// | ( -+// & ( -+// ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ) -+// ) -+// ); + + type B1 = + | A + // A comment to force break + | B; + type B2 = + | A + // A comment to force break + | B; ``` -**Prettier Similarity**: 0.00% +**Prettier Similarity**: 76.60% # typescript/union/consistent-with-flow/within-tuple.ts diff --git a/crates/biome_js_formatter/report_incompatible.md b/crates/biome_js_formatter/report_incompatible.md index 4868cf52b949..7bd5dce4846f 100644 --- a/crates/biome_js_formatter/report_incompatible.md +++ b/crates/biome_js_formatter/report_incompatible.md @@ -1,6 +1,6 @@ # Overall Metrics -**Average compatibility**: 95.62 +**Average compatibility**: 95.46
Definition @@ -8,7 +8,7 @@ $$average = \frac\{\sum_{file}^\{files}compatibility_\{file}}\{files}$$
- **Compatible lines**: 96.05 + **Compatible lines**: 95.52
Definition @@ -863,6 +863,155 @@ **Prettier Similarity**: 0.00% +# js/assignment/issue-15534.js +```diff +-params["redirectTo"] = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params[ ++ "redirectTo" ++] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +-params["redirectTo"]["codePointAt"]["name"] = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params["redirectTo"]["codePointAt"][ ++ "name" ++] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +-params.redirectTo.bar.bar.ba.barab["foo"].abr = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params.redirectTo.bar.bar.ba.barab[ ++ "foo" ++].abr = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +``` + +**Prettier Similarity**: 18.18% + + +# js/binary-expressions/in_instanceof.js +```diff +-(!foo) in bar; +-(!foo) in bar; ++!foo in bar; ++!foo in bar; + !(foo in bar); +-(!foo) in bar; ++!foo in bar; + +-(!foo) instanceof Bar; +-(!foo) instanceof Bar; ++!foo instanceof Bar; ++!foo instanceof Bar; + !(foo instanceof Bar); +-(!foo) instanceof Bar; ++!foo instanceof Bar; + +-(~foo) in bar; +-(~foo) in bar; ++~foo in bar; ++~foo in bar; + ~(foo in bar); +-(~foo) in bar; ++~foo in bar; + +-(~foo) instanceof Bar; +-(~foo) instanceof Bar; ++~foo instanceof Bar; ++~foo instanceof Bar; + ~(foo instanceof Bar); +-(~foo) instanceof Bar; ++~foo instanceof Bar; + +-(+foo) in bar; +-(+foo) in bar; +++foo in bar; +++foo in bar; + +(foo in bar); +-(+foo) in bar; +++foo in bar; + +-(+foo) instanceof Bar; +-(+foo) instanceof Bar; +++foo instanceof Bar; +++foo instanceof Bar; + +(foo instanceof Bar); +-(+foo) instanceof Bar; +++foo instanceof Bar; + +-(-foo) in bar; +-(-foo) in bar; ++-foo in bar; ++-foo in bar; + -(foo in bar); +-(-foo) in bar; ++-foo in bar; + +-(-foo) instanceof Bar; +-(-foo) instanceof Bar; ++-foo instanceof Bar; ++-foo instanceof Bar; + -(foo instanceof Bar); +-(-foo) instanceof Bar; ++-foo instanceof Bar; + +-(void 0) in bar; +-(void 0) in bar; ++void 0 in bar; ++void 0 in bar; + void (0 in bar); +-(void 0) in bar; ++void 0 in bar; + +-(void 0) instanceof bar; +-(void 0) instanceof bar; ++void 0 instanceof bar; ++void 0 instanceof bar; + void (0 instanceof bar); +-(void 0) instanceof bar; ++void 0 instanceof bar; + +-(delete 0) in bar; +-(delete 0) in bar; ++delete 0 in bar; ++delete 0 in bar; + delete (0 in bar); +-(delete 0) in bar; ++delete 0 in bar; + +-(delete 0) instanceof bar; +-(delete 0) instanceof bar; ++delete 0 instanceof bar; ++delete 0 instanceof bar; + delete (0 instanceof bar); +-(delete 0) instanceof bar; ++delete 0 instanceof bar; + +-(typeof 0) in bar; +-(typeof 0) in bar; ++typeof 0 in bar; ++typeof 0 in bar; + typeof (0 in bar); +-(typeof 0) in bar; ++typeof 0 in bar; + +-(typeof 0) instanceof bar; +-(typeof 0) instanceof bar; ++typeof 0 instanceof bar; ++typeof 0 instanceof bar; + typeof (0 instanceof bar); +-(typeof 0) instanceof bar; ++typeof 0 instanceof bar; + + ++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid + +-(!!foo) instanceof Bar; ++!!foo instanceof Bar; + +``` + +**Prettier Similarity**: 41.10% + + # js/chain-expression/test.js ```diff -(a?.b).c; @@ -896,30 +1045,6 @@ **Prettier Similarity**: 33.33% -# js/comments-closure-typecast/styled-components.js -```diff - const OverlapWrapper = - /** @type {import('styled-components').ThemedStyledFunction<'div',null,{overlap: boolean}>} */ - (styled.div)` -- position: relative; -+position:relative; - > { -- position: absolute; -- bottom: ${(p) => p.overlap === "previous" && 0}; -- top: ${(p) => p.overlap === "next" && 0}; -- } -- `; -+ position: absolute; -+ bottom: ${(p) => p.overlap === "previous" && 0}; -+top: ${(p) => p.overlap === "next" && 0}; -+} -+`; - -``` - -**Prettier Similarity**: 40.00% - - # js/comments/empty-statements.js ```diff -a; /* a */ // b @@ -1056,18 +1181,6 @@ **Prettier Similarity**: 50.00% -# js/comments/html-like/comment.js -```diff - - -``` - -**Prettier Similarity**: 66.67% - - # js/comments/jsdoc-nestled-dangling.js ```diff { @@ -1560,11 +1673,14 @@ */ foo : test - ? /* comment +- ? /* comment ++ ? /* comment comment comment */ - foo - : bar; +- foo +- : bar; ++ foo ++ : bar; test ? /* comment */ foo : bar; @@ -1585,13 +1701,17 @@ comment A newline will be added after this comment, unfortunately – but it can be removed manually, see next statement. */ - test - ? foo - : /* comment +- test +- ? foo +- : /* comment ++ test ++ ? foo ++ : /* comment comment comment */ - bar; +- bar; ++ bar; // It is at least possible to delete the extra newline that was // unfortunately added before the second condition above: @@ -1604,13 +1724,16 @@ comment */ - : test +- ? foo +- : /* comment + test - ? foo - : /* comment ++ ? foo ++ : /* comment comment comment */ - bar; +- bar; ++ bar; test ? foo : /* comment */ bar; @@ -1623,7 +1746,434 @@ ``` -**Prettier Similarity**: 97.56% +**Prettier Similarity**: 89.43% + + +# js/conditional/new-ternary-examples.js +```diff + // 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); ++ ? "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."; ++ ? "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."; ++ ? "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, ++ ? definition.default ++ : null, + ) + : typeof row[field] !== "undefined" +- ? row[field] +- : typeof definition.default !== "undefined" +- ? definition.default +- : null; ++ ? 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]; ++ ? 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} ++ ? 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; ++ ? 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()} ++ ? 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 : ( + + )} +
+ ); + +``` + +**Prettier Similarity**: 73.33% + + +# js/conditional/new-ternary-spec.js +```diff + // 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(); ++ ? bark() ++ : silent(); + + // nested ternary in consequent always breaks: + const chainedWithTernaryConsequent = isCat() + ? aNestedCondition + ? theResult() + : theAlternate() + : isDog() +- ? bark() +- : silent(); ++ ? bark() ++ : silent(); + + // consequent and terminal alternate break: + const consequentAndTerminalAlternateBreak = isCat() + ? someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : isDog() +- ? bark() +- : someReallyLargeExpression +- .thatWouldCauseALineBreak() +- .willCauseAnIndentButNotParens(); ++ ? 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(); ++ (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"; ++ ? "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"; ++ ? "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, ++ ? 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() ? ( + + ) : ( + + ) + } + /> + ); + +``` + +**Prettier Similarity**: 84.90% # js/conditional/postfix-ternary-regressions.js @@ -1667,15 +2217,19 @@ return !linkTo ? false : typeof linkTo === "function" - ? linkTo(record, reference) - : linkToRecord(rootPath, sourceId, linkTo_as_string); +- ? linkTo(record, reference) +- : linkToRecord(rootPath, sourceId, linkTo_as_string); ++ ? 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 }); +- ? " " // em space, forces the display of an empty line of normal height +- : translate(emptyText, { _: emptyText }); ++ ? " " // em space, forces the display of an empty line of normal height ++ : translate(emptyText, { _: emptyText }); } // Function call ideally wouldnt break break @@ -1722,13 +2276,17 @@ payload ? payload.id || (payload.data ? payload.data.id : null) : requestPayload - ? requestPayload.id - : null, +- ? requestPayload.id +- : null, ++ ? requestPayload.id ++ : null, payload && payload.data ? payload.data : requestPayload && requestPayload.data - ? requestPayload.data - : null, +- ? requestPayload.data +- : null, ++ ? requestPayload.data ++ : null, ); const delayedDataProvider = new Proxy(restProvider, { @@ -1774,9 +2332,12 @@ const badComments = schema.model ? schema : // If model is an array where the items schema is a referred model then we need to use that - schema.type === "array" - ? schema.items - : schema; +- schema.type === "array" +- ? schema.items +- : schema; ++ schema.type === "array" ++ ? schema.items ++ : schema; const anotherBadComment = refModel ? // If we're in a shared params file then reference the model name directly @@ -1789,7 +2350,7 @@ ``` -**Prettier Similarity**: 98.08% +**Prettier Similarity**: 91.03% # js/destructuring/destructuring.js @@ -1861,58 +2422,6 @@ **Prettier Similarity**: 91.67% -# js/explicit-resource-management/valid-await-using-binding-escaped.js -```diff - async function f() { -- await using ab = c; -+ await using \u0061b = c; - } - -``` - -**Prettier Similarity**: 66.67% - - -# js/explicit-resource-management/valid-await-using-comments.js -```diff - async function f() { - { -- /*0*/ await using /*1*/ /*2*/ b /*3*/ = /*4*/ f(); /*5*/ -+ /*0*/ await using /*1*/ /*2*/ b /*3*/ = /*4*/ f() /*5*/; - } - { - /*0*/ for ( - /*1*/ /*2*/ await using /*3*/ /*4*/ b /*5*/ = - /*6*/ x /*7*/ /*8*/ /*9*/ /*10*/; - ; -- - ); - } - { - /*0*/ for (/*1*/ /*2*/ await using /*3*/ /*4*/ b /*5*/ of /*6*/ x /*7*/ /*8*/); - } - { - /*0*/ for await (/*1*/ /*2*/ /*3*/ await using /*4*/ /*5*/ b /*6*/ of /*7*/ x /*8*/ /*9*/); - } - } - -``` - -**Prettier Similarity**: 89.47% - - -# js/explicit-resource-management/valid-using-binding-escaped.js -```diff - { -- using ab = c; -+ using \u0061b = c; - } - -``` - -**Prettier Similarity**: 66.67% - - # js/export-default/escaped/default-escaped.js ```diff // export asyn\u{63} from "async"; @@ -2649,6 +3158,15 @@ **Prettier Similarity**: 42.86% +# js/range/whitespace.js +```diff +- + +``` + +**Prettier Similarity**: 0.00% + + # js/return-outside-function/return-outside-function.js ```diff -return ( @@ -2759,9 +3277,8 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = goog.getMsg("That's all we know"); --export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = goog.getMsg( -- "That's all we know", --); +-export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = +- goog.getMsg("That's all we know"); +// FIXME +// TODO: reformat issue +// export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = @@ -2814,114 +3331,6 @@ **Prettier Similarity**: 74.07% -# js/template-literals/indention.js -```diff - [ - ` - 1. Go to "-{chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer" - )}" ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - `, - ` - 2. Go to "${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )}" ${chalk.green.underline( -- "https://www.example.com/drupedalKangarooTransformer", -- )} -+ "https://www.example.com/drupedalKangarooTransformer", -+ )} - `, - ` - 1. Go to "-{chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer" - )}" ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - 2. Go to "${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )}" ${chalk.green.underline( -- "https://www.example.com/drupedalKangarooTransformer", -- )} -+ "https://www.example.com/drupedalKangarooTransformer", -+ )} - `, - ` - 2. Go to "${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )}" ${chalk.green.underline( -- "https://www.example.com/drupedalKangarooTransformer", -- )} -+ "https://www.example.com/drupedalKangarooTransformer", -+ )} - 1. Go to "-{chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer" - )}" ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - `, - ` - 1. Go to "-{chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer" - )}" ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - 2. Go to "${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )}" ${chalk.green.underline( -- "https://www.example.com/drupedalKangarooTransformer", -- )} -+ "https://www.example.com/drupedalKangarooTransformer", -+ )} - `, - ` - 1. Go to "-{chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer" - )}" ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - 2. Go to "${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )}" ${chalk.green.underline( -- "https://www.example.com/drupedalKangarooTransformer", -- )} -+ "https://www.example.com/drupedalKangarooTransformer", -+ )} - `, - ` - # blabla ${a} ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - - 2. Go to "${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )}" - - # blabla ${a} ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - `, - ` - # blabla ${a} ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - - 2. Go to "${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )}" - - # blabla ${a} ${chalk.green.underline( - "https://www.example.com/drupedalKangarooTransformer", - )} - `, - ]; - -``` - -**Prettier Similarity**: 88.89% - - # js/ternaries/func-call.js ```diff fn( @@ -2940,6 +3349,407 @@ **Prettier Similarity**: 88.89% +# js/ternaries/indent.js +```diff + aaaaaaaaaaaaaaa + ? bbbbbbbbbbbbbbbbbb + : ccccccccccccccc +- ? ddddddddddddddd +- : eeeeeeeeeeeeeee +- ? fffffffffffffff +- : gggggggggggggggg; ++ ? ddddddddddddddd ++ : eeeeeeeeeeeeeee ++ ? fffffffffffffff ++ : gggggggggggggggg; + + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; + + a + ? { + a: 0, + } + : { + a: { + a: 0, + } + ? { + a: 0, + } + : { + y: { + a: 0, + } + ? { + a: 0, + } + : { + a: 0, + }, + }, + }; + + a + ? { + a: function () { + return a + ? { + a: [ + a + ? { + a: 0, + b: [a ? [0, 1] : []], + } + : [ + [ + 0, + { + a: 0, + }, + a ? 0 : 1, + ], + function () { + return a + ? { + a: 0, + } + : [ + { + a: 0, + }, + {}, + ]; + }, + ], + ], + } + : [ + a + ? function () { + a + ? a( + a + ? { + a: a({ + a: 0, + }), + } + : [ + 0, + a(), + a( + a(), + { + a: 0, + }, + a + ? a() + : a({ + a: 0, + }), + ), + a() + ? { + a: a(), + b: [], + } + : {}, + ], + ) + : a( + a() + ? { + a: 0, + } + : (function (a) { + return a() + ? [ + { + a: 0, + b: a(), + }, + ] + : a([ + a + ? { + a: 0, + } + : {}, + { + a: 0, + }, + ]); + })( + a + ? function (a) { + return function () { + return 0; + }; + } + : function (a) { + return function () { + return 1; + }; + }, + ), + ); + } + : function () {}, + ]; + }, + } + : a; + +``` + +**Prettier Similarity**: 97.33% + + +# js/ternaries/nested-in-condition.js +```diff + $var = ( + $number % 10 >= 2 && ($number % 100 < 10 || $number % 100 >= 20) + ? kochabCooieGameOnOboleUnweave + : annularCooeedSplicesWalksWayWay + ) + ? anodyneCondosMalateOverateRetinol + : averredBathersBoxroomBuggyNurl; + + const value = ( + bifornCringerMoshedPerplexSawder + ? askTrovenaBeenaDependsRowans + : glimseGlyphsHazardNoopsTieTie + ) + ? true + ? true + : false + : true +- ? true +- : false; ++ ? true ++ : false; + + ( + bifornCringerMoshedPerplexSawder + ? askTrovenaBeenaDependsRowans + : glimseGlyphsHazardNoopsTieTie + ) ? ( + + + + + + + + + ) : ( + + + + + + ); + +``` + +**Prettier Similarity**: 95.00% + + +# js/ternaries/nested.js +```diff + let icecream = + what == "cone" + ? (p) => (!!p ? `here's your ${p} cone` : `just the empty cone for you`) + : (p) => `here's your ${p} ${what}`; + + const value = condition1 + ? value1 + : condition2 +- ? value2 +- : condition3 +- ? value3 +- : value4; ++ ? value2 ++ : condition3 ++ ? value3 ++ : value4; + + const StorybookLoader = ({ match }) => + match.params.storyId === "button" ? ( + + ) : match.params.storyId === "color" ? ( + + ) : match.params.storyId === "typography" ? ( + + ) : match.params.storyId === "loading" ? ( + + ) : match.params.storyId === "deal-list" ? ( + + ) : ( + + {"Missing story book"} + + + + + ); + + const message = + i % 3 === 0 && i % 5 === 0 + ? "fizzbuzz" + : i % 3 === 0 +- ? "fizz" +- : i % 5 === 0 +- ? "buzz" +- : String(i); ++ ? "fizz" ++ : i % 5 === 0 ++ ? "buzz" ++ : String(i); + + const paymentMessage = + 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."; ++ ? "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 paymentMessage2 = + state == "success" + ? 1 //'Payment completed successfully' + : state == "processing" +- ? 2 //'Payment processing' +- : state == "invalid_cvc" +- ? 3 //'There was an issue with your CVC number' +- : true //state == 'invalid_expiry' +- ? 4 //'Expiry must be sometime in the past.' +- : 5; // 'There was an issue with the payment. Please contact support.' ++ ? 2 //'Payment processing' ++ : state == "invalid_cvc" ++ ? 3 //'There was an issue with your CVC number' ++ : true //state == 'invalid_expiry' ++ ? 4 //'Expiry must be sometime in the past.' ++ : 5; // 'There was an issue with the payment. Please contact support.' + + const foo = ( +
+ {medals[0].record + ? i18n("Record") + : medals[0].unique +- ? i18n("Unique") +- : medals[0].type === 0 +- ? i18n("Silver") +- : medals[0].type === 1 +- ? i18n("Gold") +- : medals[0].type === 2 +- ? i18n("Platinum") +- : i18n("Theme")} ++ ? i18n("Unique") ++ : medals[0].type === 0 ++ ? i18n("Silver") ++ : medals[0].type === 1 ++ ? i18n("Gold") ++ : medals[0].type === 2 ++ ? i18n("Platinum") ++ : i18n("Theme")} +
+ ); + + a + ? literalline + : { +- 123: 12, +- } +- ? line +- : softline; ++ 123: 12, ++ } ++ ? 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, ++ ? error.message ++ : undefined, + }, + ); + refresh(); + }, + }; + + showNotification( + typeof error === "string" ? error : error.message || body, + level || "warning", + { + messageArgs, + undoable: false, + }, + ); + + const result = + children && !isEmptyChildren(children) + ? children + : props.match +- ? component +- ? React.createElement(component, props) +- : render +- ? render(props) +- : null +- : null; ++ ? component ++ ? React.createElement(component, props) ++ : render ++ ? render(props) ++ : null ++ : null; + +``` + +**Prettier Similarity**: 69.78% + + # js/test-declarations/angularjs_inject.js ```diff beforeEach(inject(($fooService, $barService) => { @@ -3388,6 +4198,177 @@ **Prettier Similarity**: 77.36% +# jsx/jsx/conditional-expression.js +```diff + // There are two ways to print ConditionalExpressions: "normal mode" and + // "JSX mode". This is normal mode (when breaking): + // + // test + // ? consequent + // : alternate; + // + // And this is JSX mode (when breaking): + // + // test ? ( + // consequent + // ) : ( + // alternate + // ); + // + // When non-breaking, they look the same: + // + // test ? consequent : alternate; + // + // We only print a conditional expression in JSX mode if its test, + // consequent, or alternate are JSXElements. + // Otherwise, we print in normal mode. + + // This ConditionalExpression has no JSXElements so it prints in normal mode. + // The line does not break. + normalModeNonBreaking ? "a" : "b"; + + // This ConditionalExpression has no JSXElements so it prints in normal mode. + // Its consequent is very long, so it breaks out to multiple lines. + normalModeBreaking + ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa + : "c"; + + // This ConditionalExpression prints in JSX mode because its test is a + // JSXElement. It is non-breaking. + // Note: I have never, ever seen someone use a JSXElement as the test in a + // ConditionalExpression. But this test is included for completeness. +
? jsxModeFromElementNonBreaking : "a"; + + // This ConditionalExpression prints in JSX mode because its consequent is a + // JSXElement. It is non-breaking. + jsxModeFromElementNonBreaking ?
: "a"; + + // This ConditionalExpression prints in JSX mode because its alternate is a + // JSXElement. It is non-breaking. + jsxModeFromElementNonBreaking ? "a" :
; + + // This ConditionalExpression prints in JSX mode because its test is a + // JSXElement. It is breaking. + // Note: I have never, ever seen someone use a JSXElement as the test in a + // ConditionalExpression. But this test is included for completeness. +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
? ( + "jsx mode from element breaking" + ) : ( + "a" + ); + + // This ConditionalExpression prints in JSX mode because its consequent is a + // JSXElement. It is breaking. + jsxModeFromElementBreaking ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ) : ( + "a" + ); + + // This ConditionalExpression prints in JSX mode because its alternate is a + // JSXElement. It is breaking. + jsxModeFromElementBreaking ? ( + "a" + ) : ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ); + + // This chain of ConditionalExpressions prints in JSX mode because the parent of + // the outermost ConditionalExpression is a JSXExpressionContainer. It is + // 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"} ++ ? "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"; + + // This chain of ConditionalExpressions prints in JSX mode because there is a + // JSX element somewhere in the chain (in this case, at the end). It is + // breaking; notice the consequents and alternates in the entire chain get + // wrapped in parens. + cable ? ( + "satellite" + ) : isPublic ? ( + "affairs" + ) : network ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ) : ( + "dunno" + ); + + // This chain of ConditionalExpressions prints in JSX mode because there is a + // JSX element somewhere in the chain (in this case, at the beginning). It is + // breaking; notice the consequents and alternates in the entire chain get + // wrapped in parens. + cable ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+ ) : sateline ? ( + "public" + ) : affairs ? ( + "network" + ) : ( + "dunno" + ); + + // This chain of ConditionalExpressions prints in JSX mode because there is a + // JSX element somewhere in the chain. It is breaking; notice the consequents + // and alternates in the entire chain get wrapped in parens. +
+ {properties.length > 1 || + (properties.length === 1 && properties[0].apps.size > 1) ? ( + draggingApp == null || newPropertyName == null ? ( + + ) : ( + + ) + ) : null} +
; + + // #3552 + foo ? ( + + loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong jsx + + ) : undefined; + +``` + +**Prettier Similarity**: 98.76% + + # jsx/jsx/quotes.js ```diff
; @@ -3598,36 +4579,6 @@ **Prettier Similarity**: 84.38% -# jsx/template/styled-components.js -```diff - ; - - ; - - ; - -``` - -**Prettier Similarity**: 78.95% - - # jsx/text-wrap/test.js ```diff // Wrapping text @@ -4257,7 +5208,7 @@ ```diff // expression statemnt of "as" expression hardly ever makes sense, but it's still valid. const [type, x] = [0, 0]; --type as unknown; +-(type) as unknown; +// FIXME +// TODO: parse issue +// (type) as unknown; @@ -4539,22 +5490,6 @@ **Prettier Similarity**: 84.62% -# typescript/comments/ts-parameter-proerty.ts -```diff - class A { -- constructor(private readonly paramProp: Type) // comment -- {} -+ constructor( -+ private readonly paramProp: Type, -+ // comment -+ ) {} - } - -``` - -**Prettier Similarity**: 33.33% - - # typescript/comments/type-parameters.ts ```diff functionName(); @@ -4663,6 +5598,236 @@ **Prettier Similarity**: 89.19% +# typescript/conditional-types/comments.ts +```diff + type A = B extends T + ? // comment + foo + : bar; + + type A = B extends test /* comment + comment + comment + */ + ? foo + : bar; + + type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : bar; + + type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : test extends B +- ? /* comment ++ ? /* comment + comment + comment */ +- foo +- : bar; ++ foo ++ : bar; + + type T = test extends B ? /* comment */ foo : bar; + + type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ + bar; + + type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ +- test extends B +- ? foo +- : /* comment ++ test extends B ++ ? foo ++ : /* comment + comment + comment + */ +- bar; ++ bar; + + type T = test extends B ? foo : /* comment */ bar; + + type T = test extends B + ? test extends B /* c + c */ + ? foo + : bar + : bar; + +``` + +**Prettier Similarity**: 89.86% + + +# typescript/conditional-types/conditonal-types.ts +```diff + export type DeepReadonly = T extends any[] + ? DeepReadonlyArray + : T extends object +- ? DeepReadonlyObject +- : T; ++ ? DeepReadonlyObject ++ : T; + + type NonFunctionPropertyNames = { + [K in keyof T]: T[K] extends Function ? never : K; + }[keyof T]; + + interface DeepReadonlyArray extends ReadonlyArray> {} + + type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; + }; + + type TypeName = T extends string + ? "string" + : T extends number +- ? "number" +- : T extends boolean +- ? "boolean" +- : T extends undefined +- ? "undefined" +- : T extends Function +- ? "function" +- : "object"; ++ ? "number" ++ : T extends boolean ++ ? "boolean" ++ : T extends undefined ++ ? "undefined" ++ : T extends Function ++ ? "function" ++ : "object"; + + type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type02 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type03 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type04 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type05 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + type Type06 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + type Type07 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + type Type08 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + + type T1 = () => void extends T ? U : V; + type T1a = () => void extends T ? U : V; + type T1b = () => void extends T ? U : V; + type T2 = (() => void) extends T ? U : V; + + type U1 = new () => X extends T ? U : V; + type U1a = new () => X extends T ? U : V; + type U1b = new () => X extends T ? U : V; + type U2 = (new () => X) extends T ? U : V; + +``` + +**Prettier Similarity**: 78.26% + + +# typescript/conditional-types/infer-type.ts +```diff + type TestReturnType any> = T extends ( + ...args: any[] + ) => infer R + ? R + : any; + + type Unpacked = T extends (infer U)[] + ? U + : T extends (...args: any[]) => infer U +- ? U +- : T extends Promise +- ? U +- : T; ++ ? U ++ : T extends Promise ++ ? U ++ : T; + +``` + +**Prettier Similarity**: 69.23% + + +# typescript/conditional-types/new-ternary-spec.ts +```diff + // 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"; ++ ? "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; ++ ? SomeReallyLongThingThatBreaksTheLine ++ : T extends Promise ++ ? U ++ : T; + +``` + +**Prettier Similarity**: 67.57% + + # typescript/conditional-types/parentheses.ts ```diff // #13275 @@ -5238,16 +6403,6 @@ **Prettier Similarity**: 33.33% -# typescript/conformance/types/moduleDeclaration/kind-detection.ts -```diff --declare namespace /* module */ A {} -+declare /* module */ namespace A {} - -``` - -**Prettier Similarity**: 0.00% - - # typescript/custom/abstract/abstractProperties.ts ```diff abstract class Foo { @@ -5541,15 +6696,14 @@ // note lack of trailing comma in the index signature type TooLongSingleParam = { -- [ -- looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: string -- ]: string; -+ [looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: string]: string; + [ + looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong: string + ]: string; }; ``` -**Prettier Similarity**: 38.71% +**Prettier Similarity**: 48.39% # typescript/error-recovery/jsdoc_only_types.ts @@ -5850,6 +7004,25 @@ **Prettier Similarity**: 69.77% +# typescript/keyword-types/conditional-types.ts +```diff + export type UnwrappedResultRow = { + [P in keyof T]: T[P] extends Req + ? a + : T[P] extends Opt +- ? b +- : // TEST +- never; ++ ? b ++ : // TEST ++ never; + }; + +``` + +**Prettier Similarity**: 62.50% + + # typescript/last-argument-expansion/decorated-function.tsx ```diff -const Counter = decorator("my-counter")((props: { @@ -6327,22 +7500,21 @@ return 2; default: // exhaustiveness check idiom - type satisfies never; +- (type) satisfies never; ++ type satisfies never; throw new Error("unreachable"); } }; function needParens() { -- let satisfies unknown; -- interface satisfies unknown; -+ (let) satisfies unknown; -+ (interface) satisfies unknown; - module satisfies unknown; - using satisfies unknown; -- yield satisfies unknown; -- await satisfies unknown; -+ (yield) satisfies unknown; -+ (await) satisfies unknown; + (let) satisfies unknown; + (interface) satisfies unknown; +- (module) satisfies unknown; +- (using) satisfies unknown; ++ module satisfies unknown; ++ using satisfies unknown; + (yield) satisfies unknown; + (await) satisfies unknown; } function noNeedParens() { @@ -6355,7 +7527,8 @@ function satisfiesChain() { satisfies satisfies satisfies satisfies satisfies; - type satisfies never satisfies unknown; +- (type) satisfies never satisfies unknown; ++ type satisfies never satisfies unknown; } ``` @@ -6608,6 +7781,28 @@ **Prettier Similarity**: 80.00% +# typescript/union/comments.ts +```diff + type Foo = ( + | "thing1" // Comment1 +- | "thing2" // Comment2 +-)[]; // Final comment1 ++ | "thing2" ++)[]; // Comment2 // Final comment1 + + type Foo = ( + | "thing1" // Comment1 +- | "thing2" // Comment2 +-) & ++ | "thing2" ++) & // Comment2 + Bar; // Final comment2 + +``` + +**Prettier Similarity**: 60.00% + + # typescript/union/consistent-with-flow/prettier-ignore.ts ```diff export type a = @@ -6646,95 +7841,40 @@ # typescript/union/consistent-with-flow/single-type.ts ```diff --type A1 = -- | A -- // A comment to force break -- | B; --type A2 = -- | ( -- | A -- // A comment to force break -- | B -- ) -- | ( -- | A -- // A comment to force break -- | B -- ); --type A3 = -- | A -- // A comment to force break -- | B; --type A4 = -- | A -- // A comment to force break -- | B; --type A5 = -- | ({ key: string } | { key: string } | { key: string } | { key: string }) -- | { key: string } -- | { key: string }; + type A1 = + | A + // A comment to force break + | B; + type A2 = + | ( + | A + // A comment to force break + | B + ) + | ( + | A + // A comment to force break + | B + ); + type A3 = + | A + // A comment to force break + | B; + type A4 = + | A + // A comment to force break + | B; + type A5 = + | ({ key: string } | { key: string } | { key: string } | { key: string }) + | { key: string } + | { key: string }; -type A6 = - /*1*/ - | A - // A comment to force break - | B; -- --type B1 = -- | A -- // A comment to force break -- | B; --type B2 = -- | A -- // A comment to force break -- | B; +// FIXME -+// TODO: we emit invalid AST -+// type A1 = -+// | ( -+// | ( -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ); -+// type A2 = -+// | ( -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ); -+// type A3 = -+// | ( | ( -+// | A -+// // A comment to force break -+// | B -+// ) ); -+// type A4 = -+// | ( | ( | ( -+// | A -+// // A comment to force break -+// | B -+// ) ) ); -+// type A5 = -+// | ( -+// | ( -+// | { key: string } -+// | { key: string } -+// | { key: string } -+// | { key: string } -+// ) -+// | { key: string } -+// | { key: string } -+// ); ++// TODO: reformat issue +// type A6 = | ( +// /*1*/ | ( +// | ( @@ -6744,35 +7884,19 @@ +// ) +// ) +// ); -+// -+// type B1 = -+// | ( -+// & ( -+// ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ); -+// type B2 = -+// | ( -+// & ( -+// | ( -+// & ( -+// ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ) -+// ) -+// ); + + type B1 = + | A + // A comment to force break + | B; + type B2 = + | A + // A comment to force break + | B; ``` -**Prettier Similarity**: 0.00% +**Prettier Similarity**: 76.60% # typescript/union/single-type/single-type.ts diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.prettier-snap index 1195248356b4..6cc4245a9b93 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.prettier-snap @@ -1,11 +1,8 @@ -params[ - "redirectTo" -] = `${window.location.pathname}${window.location.search}${window.location.hash}`; +params["redirectTo"] = + `${window.location.pathname}${window.location.search}${window.location.hash}`; -params["redirectTo"]["codePointAt"][ - "name" -] = `${window.location.pathname}${window.location.search}${window.location.hash}`; +params["redirectTo"]["codePointAt"]["name"] = + `${window.location.pathname}${window.location.search}${window.location.hash}`; -params.redirectTo.bar.bar.ba.barab[ - "foo" -].abr = `${window.location.pathname}${window.location.search}${window.location.hash}`; +params.redirectTo.bar.bar.ba.barab["foo"].abr = + `${window.location.pathname}${window.location.search}${window.location.hash}`; diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.snap new file mode 100644 index 000000000000..c783ee10b96b --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/assignment/issue-15534.js.snap @@ -0,0 +1,68 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/assignment/issue-15534.js +--- + +# Input + +```js +params["redirectTo"] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +params["redirectTo"]["codePointAt"]["name"] = + `${window.location.pathname}${window.location.search}${window.location.hash}`; + +params.redirectTo.bar.bar.ba.barab["foo"].abr = + `${window.location.pathname}${window.location.search}${window.location.hash}`; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -1,8 +1,11 @@ +-params["redirectTo"] = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params[ ++ "redirectTo" ++] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +-params["redirectTo"]["codePointAt"]["name"] = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params["redirectTo"]["codePointAt"][ ++ "name" ++] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +-params.redirectTo.bar.bar.ba.barab["foo"].abr = +- `${window.location.pathname}${window.location.search}${window.location.hash}`; ++params.redirectTo.bar.bar.ba.barab[ ++ "foo" ++].abr = `${window.location.pathname}${window.location.search}${window.location.hash}`; +``` + +# Output + +```js +params[ + "redirectTo" +] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +params["redirectTo"]["codePointAt"][ + "name" +] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + +params.redirectTo.bar.bar.ba.barab[ + "foo" +].abr = `${window.location.pathname}${window.location.search}${window.location.hash}`; +``` + +# Lines exceeding max width of 80 characters +``` + 3: ] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + 7: ] = `${window.location.pathname}${window.location.search}${window.location.hash}`; + 11: ].abr = `${window.location.pathname}${window.location.search}${window.location.hash}`; +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.prettier-snap index bdbcb89dd491..5c046f3e568e 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.prettier-snap @@ -1,73 +1,73 @@ -!foo in bar; -!foo in bar; +(!foo) in bar; +(!foo) in bar; !(foo in bar); -!foo in bar; +(!foo) in bar; -!foo instanceof Bar; -!foo instanceof Bar; +(!foo) instanceof Bar; +(!foo) instanceof Bar; !(foo instanceof Bar); -!foo instanceof Bar; +(!foo) instanceof Bar; -~foo in bar; -~foo in bar; +(~foo) in bar; +(~foo) in bar; ~(foo in bar); -~foo in bar; +(~foo) in bar; -~foo instanceof Bar; -~foo instanceof Bar; +(~foo) instanceof Bar; +(~foo) instanceof Bar; ~(foo instanceof Bar); -~foo instanceof Bar; +(~foo) instanceof Bar; -+foo in bar; -+foo in bar; +(+foo) in bar; +(+foo) in bar; +(foo in bar); -+foo in bar; +(+foo) in bar; -+foo instanceof Bar; -+foo instanceof Bar; +(+foo) instanceof Bar; +(+foo) instanceof Bar; +(foo instanceof Bar); -+foo instanceof Bar; +(+foo) instanceof Bar; --foo in bar; --foo in bar; +(-foo) in bar; +(-foo) in bar; -(foo in bar); --foo in bar; +(-foo) in bar; --foo instanceof Bar; --foo instanceof Bar; +(-foo) instanceof Bar; +(-foo) instanceof Bar; -(foo instanceof Bar); --foo instanceof Bar; +(-foo) instanceof Bar; -void 0 in bar; -void 0 in bar; +(void 0) in bar; +(void 0) in bar; void (0 in bar); -void 0 in bar; +(void 0) in bar; -void 0 instanceof bar; -void 0 instanceof bar; +(void 0) instanceof bar; +(void 0) instanceof bar; void (0 instanceof bar); -void 0 instanceof bar; +(void 0) instanceof bar; -delete 0 in bar; -delete 0 in bar; +(delete 0) in bar; +(delete 0) in bar; delete (0 in bar); -delete 0 in bar; +(delete 0) in bar; -delete 0 instanceof bar; -delete 0 instanceof bar; +(delete 0) instanceof bar; +(delete 0) instanceof bar; delete (0 instanceof bar); -delete 0 instanceof bar; +(delete 0) instanceof bar; -typeof 0 in bar; -typeof 0 in bar; +(typeof 0) in bar; +(typeof 0) in bar; typeof (0 in bar); -typeof 0 in bar; +(typeof 0) in bar; -typeof 0 instanceof bar; -typeof 0 instanceof bar; +(typeof 0) instanceof bar; +(typeof 0) instanceof bar; typeof (0 instanceof bar); -typeof 0 instanceof bar; +(typeof 0) instanceof bar; ++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid -!!foo instanceof Bar; +(!!foo) instanceof Bar; diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.snap new file mode 100644 index 000000000000..ff0169c6bbc8 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/binary-expressions/in_instanceof.js.snap @@ -0,0 +1,293 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/binary-expressions/in_instanceof.js +--- + +# Input + +```js +!foo in bar; +(!foo in bar); +!(foo in bar); +(!foo) in bar; + +!foo instanceof Bar; +(!foo instanceof Bar); +!(foo instanceof Bar); +(!foo) instanceof Bar; + +~foo in bar; +(~foo in bar); +~(foo in bar); +(~foo) in bar; + +~foo instanceof Bar; +(~foo instanceof Bar); +~(foo instanceof Bar); +(~foo) instanceof Bar; + ++foo in bar; +(+foo in bar); ++(foo in bar); +(+foo) in bar; + ++foo instanceof Bar; +(+foo instanceof Bar); ++(foo instanceof Bar); +(+foo) instanceof Bar; + +-foo in bar; +(-foo in bar); +-(foo in bar); +(-foo) in bar; + +-foo instanceof Bar; +(-foo instanceof Bar); +-(foo instanceof Bar); +(-foo) instanceof Bar; + +void 0 in bar; +(void 0 in bar); +void (0 in bar); +(void 0) in bar; + +void 0 instanceof bar; +(void 0 instanceof bar); +void (0 instanceof bar); +(void 0) instanceof bar; + +delete 0 in bar; +(delete 0 in bar); +delete (0 in bar); +(delete 0) in bar; + +delete 0 instanceof bar; +(delete 0 instanceof bar); +delete (0 instanceof bar); +(delete 0) instanceof bar; + +typeof 0 in bar; +(typeof 0 in bar); +typeof (0 in bar); +(typeof 0) in bar; + +typeof 0 instanceof bar; +(typeof 0 instanceof bar); +typeof (0 instanceof bar); +(typeof 0) instanceof bar; + +++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid + +!!foo instanceof Bar; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -1,73 +1,73 @@ +-(!foo) in bar; +-(!foo) in bar; ++!foo in bar; ++!foo in bar; + !(foo in bar); +-(!foo) in bar; ++!foo in bar; + +-(!foo) instanceof Bar; +-(!foo) instanceof Bar; ++!foo instanceof Bar; ++!foo instanceof Bar; + !(foo instanceof Bar); +-(!foo) instanceof Bar; ++!foo instanceof Bar; + +-(~foo) in bar; +-(~foo) in bar; ++~foo in bar; ++~foo in bar; + ~(foo in bar); +-(~foo) in bar; ++~foo in bar; + +-(~foo) instanceof Bar; +-(~foo) instanceof Bar; ++~foo instanceof Bar; ++~foo instanceof Bar; + ~(foo instanceof Bar); +-(~foo) instanceof Bar; ++~foo instanceof Bar; + +-(+foo) in bar; +-(+foo) in bar; +++foo in bar; +++foo in bar; + +(foo in bar); +-(+foo) in bar; +++foo in bar; + +-(+foo) instanceof Bar; +-(+foo) instanceof Bar; +++foo instanceof Bar; +++foo instanceof Bar; + +(foo instanceof Bar); +-(+foo) instanceof Bar; +++foo instanceof Bar; + +-(-foo) in bar; +-(-foo) in bar; ++-foo in bar; ++-foo in bar; + -(foo in bar); +-(-foo) in bar; ++-foo in bar; + +-(-foo) instanceof Bar; +-(-foo) instanceof Bar; ++-foo instanceof Bar; ++-foo instanceof Bar; + -(foo instanceof Bar); +-(-foo) instanceof Bar; ++-foo instanceof Bar; + +-(void 0) in bar; +-(void 0) in bar; ++void 0 in bar; ++void 0 in bar; + void (0 in bar); +-(void 0) in bar; ++void 0 in bar; + +-(void 0) instanceof bar; +-(void 0) instanceof bar; ++void 0 instanceof bar; ++void 0 instanceof bar; + void (0 instanceof bar); +-(void 0) instanceof bar; ++void 0 instanceof bar; + +-(delete 0) in bar; +-(delete 0) in bar; ++delete 0 in bar; ++delete 0 in bar; + delete (0 in bar); +-(delete 0) in bar; ++delete 0 in bar; + +-(delete 0) instanceof bar; +-(delete 0) instanceof bar; ++delete 0 instanceof bar; ++delete 0 instanceof bar; + delete (0 instanceof bar); +-(delete 0) instanceof bar; ++delete 0 instanceof bar; + +-(typeof 0) in bar; +-(typeof 0) in bar; ++typeof 0 in bar; ++typeof 0 in bar; + typeof (0 in bar); +-(typeof 0) in bar; ++typeof 0 in bar; + +-(typeof 0) instanceof bar; +-(typeof 0) instanceof bar; ++typeof 0 instanceof bar; ++typeof 0 instanceof bar; + typeof (0 instanceof bar); +-(typeof 0) instanceof bar; ++typeof 0 instanceof bar; + + ++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid + +-(!!foo) instanceof Bar; ++!!foo instanceof Bar; +``` + +# Output + +```js +!foo in bar; +!foo in bar; +!(foo in bar); +!foo in bar; + +!foo instanceof Bar; +!foo instanceof Bar; +!(foo instanceof Bar); +!foo instanceof Bar; + +~foo in bar; +~foo in bar; +~(foo in bar); +~foo in bar; + +~foo instanceof Bar; +~foo instanceof Bar; +~(foo instanceof Bar); +~foo instanceof Bar; + ++foo in bar; ++foo in bar; ++(foo in bar); ++foo in bar; + ++foo instanceof Bar; ++foo instanceof Bar; ++(foo instanceof Bar); ++foo instanceof Bar; + +-foo in bar; +-foo in bar; +-(foo in bar); +-foo in bar; + +-foo instanceof Bar; +-foo instanceof Bar; +-(foo instanceof Bar); +-foo instanceof Bar; + +void 0 in bar; +void 0 in bar; +void (0 in bar); +void 0 in bar; + +void 0 instanceof bar; +void 0 instanceof bar; +void (0 instanceof bar); +void 0 instanceof bar; + +delete 0 in bar; +delete 0 in bar; +delete (0 in bar); +delete 0 in bar; + +delete 0 instanceof bar; +delete 0 instanceof bar; +delete (0 instanceof bar); +delete 0 instanceof bar; + +typeof 0 in bar; +typeof 0 in bar; +typeof (0 in bar); +typeof 0 in bar; + +typeof 0 instanceof bar; +typeof 0 instanceof bar; +typeof (0 instanceof bar); +typeof 0 instanceof bar; + +++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid + +!!foo instanceof Bar; +``` + +# Lines exceeding max width of 80 characters +``` + 71: ++x instanceof bar; // not ambiguous, because ++(x instanceof bar) is obviously invalid +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.prettier-snap index 74da7828ed9e..9f0faf007961 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.prettier-snap @@ -63,11 +63,11 @@ test */ foo : test - ? /* comment + ? /* comment comment comment */ - foo - : bar; + foo + : bar; test ? /* comment */ foo : bar; @@ -88,13 +88,13 @@ test comment A newline will be added after this comment, unfortunately – but it can be removed manually, see next statement. */ - test - ? foo - : /* comment + test + ? foo + : /* comment comment comment */ - bar; + bar; // It is at least possible to delete the extra newline that was // unfortunately added before the second condition above: @@ -105,12 +105,12 @@ test comment */ : test - ? foo - : /* comment + ? foo + : /* comment comment comment */ - bar; + bar; test ? foo : /* comment */ bar; diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.snap index a404742d16f6..196139e79f21 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/comments.js.snap @@ -137,7 +137,37 @@ c */? foo : bar : bar; ```diff --- Prettier +++ Biome -@@ -99,12 +99,13 @@ +@@ -63,11 +63,11 @@ + */ + foo + : test +- ? /* comment ++ ? /* comment + comment + comment */ +- foo +- : bar; ++ foo ++ : bar; + + test ? /* comment */ foo : bar; + +@@ -88,29 +88,30 @@ + comment + A newline will be added after this comment, unfortunately – but it can be removed manually, see next statement. + */ +- test +- ? foo +- : /* comment ++ test ++ ? foo ++ : /* comment + comment + comment + */ +- bar; ++ bar; + // It is at least possible to delete the extra newline that was // unfortunately added before the second condition above: test @@ -149,10 +179,19 @@ c */? foo : bar : bar; comment */ - : test +- ? foo +- : /* comment + test - ? foo - : /* comment ++ ? foo ++ : /* comment comment + comment + */ +- bar; ++ bar; + + test ? foo : /* comment */ bar; + ``` # Output diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.prettier-snap index 559fdb7c9a89..c1ad9bee5b4f 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.prettier-snap @@ -8,46 +8,46 @@ const message = i % 3 === 0 && i % 5 === 0 ? "fizzbuzz" : i % 3 === 0 - ? "fizz" - : i % 5 === 0 - ? "buzz" - : String(i); + ? "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."; + ? "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."; + ? "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, + ? definition.default + : null, ) : typeof row[field] !== "undefined" - ? row[field] - : typeof definition.default !== "undefined" - ? definition.default - : null; + ? 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 @@ -59,10 +59,10 @@ const typeofExampleFlipped = definition.encode : row[field], ) : typeof row[field] === "undefined" - ? typeof definition.default === "undefined" - ? null - : definition.default - : row[field]; + ? typeof definition.default === "undefined" + ? null + : definition.default + : row[field]; // JSX Examples: @@ -83,12 +83,12 @@ const reactRouterExampleJSX = ( {children && !isEmptyChildren(children) ? children : props.match - ? component - ? React.createElement(component, props) - : render - ? render(props) - : null - : null} + ? component + ? React.createElement(component, props) + : render + ? render(props) + : null + : null}
); @@ -96,20 +96,20 @@ const reactRouterExampleNonJSX = children && !isEmptyChildren(children) ? children : props.match - ? component - ? React.createElement(component, props) - : render - ? render(props) - : null - : null; + ? 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()} + ? bark() + : someReallyLargeExpression.toMakeMeowNoise().willCauseParens()}
); diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.snap new file mode 100644 index 000000000000..102d59eb8afb --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-examples.js.snap @@ -0,0 +1,447 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/conditional/new-ternary-examples.js +--- + +# Input + +```js +// 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 + : } +
+); + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -8,46 +8,46 @@ + i % 3 === 0 && i % 5 === 0 + ? "fizzbuzz" + : i % 3 === 0 +- ? "fizz" +- : i % 5 === 0 +- ? "buzz" +- : String(i); ++ ? "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."; ++ ? "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."; ++ ? "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, ++ ? definition.default ++ : null, + ) + : typeof row[field] !== "undefined" +- ? row[field] +- : typeof definition.default !== "undefined" +- ? definition.default +- : null; ++ ? 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 +@@ -59,10 +59,10 @@ + : row[field], + ) + : typeof row[field] === "undefined" +- ? typeof definition.default === "undefined" +- ? null +- : definition.default +- : row[field]; ++ ? typeof definition.default === "undefined" ++ ? null ++ : definition.default ++ : row[field]; + + // JSX Examples: + +@@ -83,12 +83,12 @@ + {children && !isEmptyChildren(children) + ? children + : props.match +- ? component +- ? React.createElement(component, props) +- : render +- ? render(props) +- : null +- : null} ++ ? component ++ ? React.createElement(component, props) ++ : render ++ ? render(props) ++ : null ++ : null} +
+ ); + +@@ -96,20 +96,20 @@ + children && !isEmptyChildren(children) + ? children + : props.match +- ? component +- ? React.createElement(component, props) +- : render +- ? render(props) +- : null +- : null; ++ ? 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()} ++ ? bark() ++ : someReallyLargeExpression.toMakeMeowNoise().willCauseParens()} +
+ ); + +``` + +# Output + +```js +// 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 : ( + + )} +
+); +``` + +# Lines exceeding max width of 80 characters +``` + 3: // TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts + 33: ? "There was an issue with your CVC number, and you need to take a prompt action on it." + 52: // (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) +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.prettier-snap index 3778b25b9fd4..a219ce6121a8 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.prettier-snap @@ -29,8 +29,8 @@ const chainedWithLongConsequent = isCat() .thatWouldCauseALineBreak() .willCauseAnIndentButNotParens() : isDog() - ? bark() - : silent(); + ? bark() + : silent(); // nested ternary in consequent always breaks: const chainedWithTernaryConsequent = isCat() @@ -38,8 +38,8 @@ const chainedWithTernaryConsequent = isCat() ? theResult() : theAlternate() : isDog() - ? bark() - : silent(); + ? bark() + : silent(); // consequent and terminal alternate break: const consequentAndTerminalAlternateBreak = isCat() @@ -47,10 +47,10 @@ const consequentAndTerminalAlternateBreak = isCat() .thatWouldCauseALineBreak() .willCauseAnIndentButNotParens() : isDog() - ? bark() - : someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens(); + ? bark() + : someReallyLargeExpression + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens(); // multiline conditions and consequents/alternates: const multilineConditionsConsequentsAndAlternates = @@ -59,29 +59,29 @@ const multilineConditionsConsequentsAndAlternates = .thatWouldCauseALineBreak() .willCauseAnIndentButNotParens() : isNotAnAdorableKittyCat() && - (someReallyLongCondition || moreInThisLongCondition) - ? bark() - : shortCondition() - ? shortConsequent() - : someReallyLargeExpression - .thatWouldCauseALineBreak() - .willCauseAnIndentButNotParens(); + (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"; + ? "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 = @@ -99,16 +99,16 @@ const longConditionalChained = averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol() ? "foo" : anotherCondition - ? "bar" - : "baz"; + ? "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, + ? definition.default + : null, typeof row[field] === "undefined" ? typeof definition.default === "undefined" ? null diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.snap new file mode 100644 index 000000000000..1c14aa4696a0 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/new-ternary-spec.js.snap @@ -0,0 +1,522 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/conditional/new-ternary-spec.js +--- + +# Input + +```js +// 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() ? + + : + } + /> +); + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -29,8 +29,8 @@ + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : isDog() +- ? bark() +- : silent(); ++ ? bark() ++ : silent(); + + // nested ternary in consequent always breaks: + const chainedWithTernaryConsequent = isCat() +@@ -38,8 +38,8 @@ + ? theResult() + : theAlternate() + : isDog() +- ? bark() +- : silent(); ++ ? bark() ++ : silent(); + + // consequent and terminal alternate break: + const consequentAndTerminalAlternateBreak = isCat() +@@ -47,10 +47,10 @@ + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : isDog() +- ? bark() +- : someReallyLargeExpression +- .thatWouldCauseALineBreak() +- .willCauseAnIndentButNotParens(); ++ ? bark() ++ : someReallyLargeExpression ++ .thatWouldCauseALineBreak() ++ .willCauseAnIndentButNotParens(); + + // multiline conditions and consequents/alternates: + const multilineConditionsConsequentsAndAlternates = +@@ -59,29 +59,29 @@ + .thatWouldCauseALineBreak() + .willCauseAnIndentButNotParens() + : isNotAnAdorableKittyCat() && +- (someReallyLongCondition || moreInThisLongCondition) +- ? bark() +- : shortCondition() +- ? shortConsequent() +- : someReallyLargeExpression +- .thatWouldCauseALineBreak() +- .willCauseAnIndentButNotParens(); ++ (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"; ++ ? "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 = +@@ -99,16 +99,16 @@ + averredBathersBoxroomBuggyNurl().anodyneCondosMalateOverateRetinol() + ? "foo" + : anotherCondition +- ? "bar" +- : "baz"; ++ ? "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, ++ ? definition.default ++ : null, + typeof row[field] === "undefined" + ? typeof definition.default === "undefined" + ? null +``` + +# Output + +```js +// 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() ? ( + + ) : ( + + ) + } + /> +); +``` + +# Lines exceeding max width of 80 characters +``` + 3: // TypeScript is here: prettier/tests/format/typescript/conditional-types/new-ternary-spec.ts + 130: // When a ternary's parent is a JSXExpressionContainer which is not in a JSXAttribute, +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.prettier-snap index 2575c2fcacd0..93f59892607b 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.prettier-snap @@ -37,15 +37,15 @@ function foo() { return !linkTo ? false : typeof linkTo === "function" - ? linkTo(record, reference) - : linkToRecord(rootPath, sourceId, linkTo_as_string); + ? 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 }); + ? " " // em space, forces the display of an empty line of normal height + : translate(emptyText, { _: emptyText }); } // Function call ideally wouldnt break break @@ -92,13 +92,13 @@ resolveRedirectTo( payload ? payload.id || (payload.data ? payload.data.id : null) : requestPayload - ? requestPayload.id - : null, + ? requestPayload.id + : null, payload && payload.data ? payload.data : requestPayload && requestPayload.data - ? requestPayload.data - : null, + ? requestPayload.data + : null, ); const delayedDataProvider = new Proxy(restProvider, { @@ -141,9 +141,9 @@ function foo7() { const badComments = schema.model ? schema : // If model is an array where the items schema is a referred model then we need to use that - schema.type === "array" - ? schema.items - : schema; + schema.type === "array" + ? schema.items + : schema; const anotherBadComment = refModel ? // If we're in a shared params file then reference the model name directly diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.snap index 668664cae0ef..b91653500a54 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/conditional/postfix-ternary-regressions.js.snap @@ -180,7 +180,42 @@ const anotherBadComment = ```diff --- Prettier +++ Biome -@@ -103,8 +103,9 @@ +@@ -37,15 +37,15 @@ + return !linkTo + ? false + : typeof linkTo === "function" +- ? linkTo(record, reference) +- : linkToRecord(rootPath, sourceId, linkTo_as_string); ++ ? 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 }); ++ ? " " // em space, forces the display of an empty line of normal height ++ : translate(emptyText, { _: emptyText }); + } + + // Function call ideally wouldnt break break +@@ -92,19 +92,20 @@ + payload + ? payload.id || (payload.data ? payload.data.id : null) + : requestPayload +- ? requestPayload.id +- : null, ++ ? requestPayload.id ++ : null, + payload && payload.data + ? payload.data + : requestPayload && requestPayload.data +- ? requestPayload.data +- : null, ++ ? requestPayload.data ++ : null, + ); const delayedDataProvider = new Proxy(restProvider, { get: (target, name, self) => @@ -192,6 +227,19 @@ const anotherBadComment = : (resource, params) => new Promise((resolve) => setTimeout( +@@ -141,9 +142,9 @@ + const badComments = schema.model + ? schema + : // If model is an array where the items schema is a referred model then we need to use that +- schema.type === "array" +- ? schema.items +- : schema; ++ schema.type === "array" ++ ? schema.items ++ : schema; + + const anotherBadComment = refModel + ? // If we're in a shared params file then reference the model name directly ``` # Output diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.prettier-snap index e69de29bb2d1..8d1c8b69c3fc 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.prettier-snap @@ -0,0 +1 @@ + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.snap new file mode 100644 index 000000000000..87991a9ba35b --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/range/whitespace.js.snap @@ -0,0 +1,28 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/range/whitespace.js +--- + +# Input + +```js + + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -1 +0,0 @@ +- +``` + +# Output + +```js +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.prettier-snap index d095641f07d3..1c8e2209ff58 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.prettier-snap @@ -1,6 +1,5 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = goog.getMsg("That's all we know"); -export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = goog.getMsg( - "That's all we know", -); +export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = + goog.getMsg("That's all we know"); diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.snap index 20aecb270c8b..b8d107101787 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/strings/escaped.js.snap @@ -24,15 +24,14 @@ export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = ```diff --- Prettier +++ Biome -@@ -1,6 +1,9 @@ +@@ -1,5 +1,9 @@ +// FIXME +// TODO: reformat issue export const MSG_GENERIC_OPERATION_FAILURE_BODY_1 = goog.getMsg("That's all we know"); --export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = goog.getMsg( -- "That's all we know", --); +-export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = +- goog.getMsg("That's all we know"); +// FIXME +// TODO: reformat issue +// export const MSG_GENERIC_OPERATION_FAILURE_BODY_2 = diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.prettier-snap index 62330970d433..ee9d64f43abf 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.prettier-snap @@ -1,10 +1,10 @@ aaaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb : ccccccccccccccc - ? ddddddddddddddd - : eeeeeeeeeeeeeee - ? fffffffffffffff - : gggggggggggggggg; + ? ddddddddddddddd + : eeeeeeeeeeeeeee + ? fffffffffffffff + : gggggggggggggggg; aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.snap new file mode 100644 index 000000000000..5da3cad4c14e --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/indent.js.snap @@ -0,0 +1,357 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/ternaries/indent.js +--- + +# Input + +```js +aaaaaaaaaaaaaaa ? bbbbbbbbbbbbbbbbbb : ccccccccccccccc ? ddddddddddddddd : eeeeeeeeeeeeeee ? fffffffffffffff : gggggggggggggggg + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +? +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +? +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +? +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +: +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +: +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +: +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +a + ? { + a: 0 + } + : { + a: { + a: 0 + } + ? { + a: 0 + } + : { + y: { + a: 0 + } + ? { + a: 0 + } + : { + a: 0 + } + } + } + +a + ? { + a: function() { + return a + ? { + a: [ + a + ? { + a: 0, + b: [ + a + ? [ + 0, + 1 + ] + : [] + ] + } + : [ + [ + 0, + { + a: 0 + }, + a + ? 0 + : 1 + ], + function() { + return a + ? { + a: 0 + } + : [ + { + a: 0 + }, + {} + ]; + } + ] + ] + } + : [ + a + ? function() { + a + ? a( + a + ? { + a: a( + { + a: 0 + } + ) + } + : [ + 0, + a(), + a( + a(), + { + a: 0 + }, + a + ? a() + : a( + { + a: 0 + } + ) + ), + a() + ? { + a: a(), + b: [] + } + : {} + ] + ): + a( + a() + ? { + a: 0 + } + : (function(a) { + return a() + ? [ + { + a: 0, + b: a() + } + ] + : a( + [ + a + ? { + a: 0 + } + : {}, + { + a: 0 + } + ] + ); + })( + a + ? function(a) { + return function() { + return 0; + }; + } + : function(a) { + return function() { + return 1; + } + } + ) + ); + } + : function() { + + } + ]; + } + } + : a; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -1,10 +1,10 @@ + aaaaaaaaaaaaaaa + ? bbbbbbbbbbbbbbbbbb + : ccccccccccccccc +- ? ddddddddddddddd +- : eeeeeeeeeeeeeee +- ? fffffffffffffff +- : gggggggggggggggg; ++ ? ddddddddddddddd ++ : eeeeeeeeeeeeeee ++ ? fffffffffffffff ++ : gggggggggggggggg; + + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +``` + +# Output + +```js +aaaaaaaaaaaaaaa + ? bbbbbbbbbbbbbbbbbb + : ccccccccccccccc + ? ddddddddddddddd + : eeeeeeeeeeeeeee + ? fffffffffffffff + : gggggggggggggggg; + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; + +a + ? { + a: 0, + } + : { + a: { + a: 0, + } + ? { + a: 0, + } + : { + y: { + a: 0, + } + ? { + a: 0, + } + : { + a: 0, + }, + }, + }; + +a + ? { + a: function () { + return a + ? { + a: [ + a + ? { + a: 0, + b: [a ? [0, 1] : []], + } + : [ + [ + 0, + { + a: 0, + }, + a ? 0 : 1, + ], + function () { + return a + ? { + a: 0, + } + : [ + { + a: 0, + }, + {}, + ]; + }, + ], + ], + } + : [ + a + ? function () { + a + ? a( + a + ? { + a: a({ + a: 0, + }), + } + : [ + 0, + a(), + a( + a(), + { + a: 0, + }, + a + ? a() + : a({ + a: 0, + }), + ), + a() + ? { + a: a(), + b: [], + } + : {}, + ], + ) + : a( + a() + ? { + a: 0, + } + : (function (a) { + return a() + ? [ + { + a: 0, + b: a(), + }, + ] + : a([ + a + ? { + a: 0, + } + : {}, + { + a: 0, + }, + ]); + })( + a + ? function (a) { + return function () { + return 0; + }; + } + : function (a) { + return function () { + return 1; + }; + }, + ), + ); + } + : function () {}, + ]; + }, + } + : a; +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.prettier-snap index b52646b72415..f191de478cbc 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.prettier-snap @@ -15,8 +15,8 @@ const value = ( ? true : false : true - ? true - : false; + ? true + : false; ( bifornCringerMoshedPerplexSawder diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.snap new file mode 100644 index 000000000000..1b0316389600 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested-in-condition.js.snap @@ -0,0 +1,112 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/ternaries/nested-in-condition.js +--- + +# Input + +```js +$var = ($number % 10 >= 2 && ($number % 100 < 10 || $number % 100 >= 20) +? kochabCooieGameOnOboleUnweave +: annularCooeedSplicesWalksWayWay) + ? anodyneCondosMalateOverateRetinol + : averredBathersBoxroomBuggyNurl; + +const value = (bifornCringerMoshedPerplexSawder +? askTrovenaBeenaDependsRowans +: glimseGlyphsHazardNoopsTieTie) + ? true + ? true + : false + : true + ? true + : false; + +(bifornCringerMoshedPerplexSawder ? ( + askTrovenaBeenaDependsRowans +) : ( + glimseGlyphsHazardNoopsTieTie +)) ? ( + + + + + + + + +) : ( + + + + + +); + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -15,8 +15,8 @@ + ? true + : false + : true +- ? true +- : false; ++ ? true ++ : false; + + ( + bifornCringerMoshedPerplexSawder +``` + +# Output + +```js +$var = ( + $number % 10 >= 2 && ($number % 100 < 10 || $number % 100 >= 20) + ? kochabCooieGameOnOboleUnweave + : annularCooeedSplicesWalksWayWay +) + ? anodyneCondosMalateOverateRetinol + : averredBathersBoxroomBuggyNurl; + +const value = ( + bifornCringerMoshedPerplexSawder + ? askTrovenaBeenaDependsRowans + : glimseGlyphsHazardNoopsTieTie +) + ? true + ? true + : false + : true + ? true + : false; + +( + bifornCringerMoshedPerplexSawder + ? askTrovenaBeenaDependsRowans + : glimseGlyphsHazardNoopsTieTie +) ? ( + + + + + + + + +) : ( + + + + + +); +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.prettier-snap index 9fd99ffa730e..11800bb40a24 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.prettier-snap @@ -6,10 +6,10 @@ let icecream = const value = condition1 ? value1 : condition2 - ? value2 - : condition3 - ? value3 - : value4; + ? value2 + : condition3 + ? value3 + : value4; const StorybookLoader = ({ match }) => match.params.storyId === "button" ? ( @@ -35,32 +35,32 @@ const message = i % 3 === 0 && i % 5 === 0 ? "fizzbuzz" : i % 3 === 0 - ? "fizz" - : i % 5 === 0 - ? "buzz" - : String(i); + ? "fizz" + : i % 5 === 0 + ? "buzz" + : String(i); const paymentMessage = 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."; + ? "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 paymentMessage2 = state == "success" ? 1 //'Payment completed successfully' : state == "processing" - ? 2 //'Payment processing' - : state == "invalid_cvc" - ? 3 //'There was an issue with your CVC number' - : true //state == 'invalid_expiry' - ? 4 //'Expiry must be sometime in the past.' - : 5; // 'There was an issue with the payment. Please contact support.' + ? 2 //'Payment processing' + : state == "invalid_cvc" + ? 3 //'There was an issue with your CVC number' + : true //state == 'invalid_expiry' + ? 4 //'Expiry must be sometime in the past.' + : 5; // 'There was an issue with the payment. Please contact support.' const foo = (
{medals[0].record ? i18n("Record") : medals[0].unique - ? i18n("Unique") - : medals[0].type === 0 - ? i18n("Silver") - : medals[0].type === 1 - ? i18n("Gold") - : medals[0].type === 2 - ? i18n("Platinum") - : i18n("Theme")} + ? i18n("Unique") + : medals[0].type === 0 + ? i18n("Silver") + : medals[0].type === 1 + ? i18n("Gold") + : medals[0].type === 2 + ? i18n("Platinum") + : i18n("Theme")}
); a ? literalline : { - 123: 12, - } - ? line - : softline; + 123: 12, + } + ? line + : softline; const config = { onFailure: @@ -110,8 +110,8 @@ const config = { typeof error === "string" ? error : error && error.message - ? error.message - : undefined, + ? error.message + : undefined, }, ); refresh(); @@ -131,9 +131,9 @@ const result = children && !isEmptyChildren(children) ? children : props.match - ? component - ? React.createElement(component, props) - : render - ? render(props) - : null - : null; + ? component + ? React.createElement(component, props) + : render + ? render(props) + : null + : null; diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.snap new file mode 100644 index 000000000000..c11fb09664c5 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/js/ternaries/nested.js.snap @@ -0,0 +1,435 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: js/ternaries/nested.js +--- + +# Input + +```js +let icecream = what == "cone" + ? p => !!p ? `here's your ${p} cone` : `just the empty cone for you` + : p => `here's your ${p} ${what}`; + +const value = condition1 +? value1 +: condition2 + ? value2 + : condition3 + ? value3 + : value4; + + +const StorybookLoader = ({ match }) => ( + match.params.storyId === "button" + ? + : match.params.storyId === "color" + ? + : match.params.storyId === "typography" + ? + : match.params.storyId === "loading" + ? + : match.params.storyId === "deal-list" + ? + : ( + + {'Missing story book'} + + + + + ) +) + +const message = + i % 3 === 0 && i % 5 === 0 ? + 'fizzbuzz' + : i % 3 === 0 ? + 'fizz' + : i % 5 === 0 ? + 'buzz' + : + String(i) + +const paymentMessage = 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 paymentMessage2 = state == 'success' + ? 1 //'Payment completed successfully' + +: state == 'processing' + ? 2 //'Payment processing' + +: state == 'invalid_cvc' + ? 3 //'There was an issue with your CVC number' + +: true //state == 'invalid_expiry' + ? 4 //'Expiry must be sometime in the past.' + + : 5 // 'There was an issue with the payment. Please contact support.' + +const foo =
+ {medals[0].record ? ( + i18n('Record') + ) : medals[0].unique ? ( + i18n('Unique') + ) : medals[0].type === 0 ? ( + i18n('Silver') + ) : medals[0].type === 1 ? ( + i18n('Gold') + ) : medals[0].type === 2 ? ( + i18n('Platinum') + ) : ( + i18n('Theme') + )} +
+ +a + ? literalline + : { + 123: 12 + } + ? 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, + } +) + +const result = children && !isEmptyChildren(children) + ? children + : props.match + ? component + ? React.createElement(component, props) + : render + ? render(props) + : null + : null; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -6,10 +6,10 @@ + const value = condition1 + ? value1 + : condition2 +- ? value2 +- : condition3 +- ? value3 +- : value4; ++ ? value2 ++ : condition3 ++ ? value3 ++ : value4; + + const StorybookLoader = ({ match }) => + match.params.storyId === "button" ? ( +@@ -35,32 +35,32 @@ + i % 3 === 0 && i % 5 === 0 + ? "fizzbuzz" + : i % 3 === 0 +- ? "fizz" +- : i % 5 === 0 +- ? "buzz" +- : String(i); ++ ? "fizz" ++ : i % 5 === 0 ++ ? "buzz" ++ : String(i); + + const paymentMessage = + 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."; ++ ? "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 paymentMessage2 = + state == "success" + ? 1 //'Payment completed successfully' + : state == "processing" +- ? 2 //'Payment processing' +- : state == "invalid_cvc" +- ? 3 //'There was an issue with your CVC number' +- : true //state == 'invalid_expiry' +- ? 4 //'Expiry must be sometime in the past.' +- : 5; // 'There was an issue with the payment. Please contact support.' ++ ? 2 //'Payment processing' ++ : state == "invalid_cvc" ++ ? 3 //'There was an issue with your CVC number' ++ : true //state == 'invalid_expiry' ++ ? 4 //'Expiry must be sometime in the past.' ++ : 5; // 'There was an issue with the payment. Please contact support.' + + const foo = ( +
+ {medals[0].record + ? i18n("Record") + : medals[0].unique +- ? i18n("Unique") +- : medals[0].type === 0 +- ? i18n("Silver") +- : medals[0].type === 1 +- ? i18n("Gold") +- : medals[0].type === 2 +- ? i18n("Platinum") +- : i18n("Theme")} ++ ? i18n("Unique") ++ : medals[0].type === 0 ++ ? i18n("Silver") ++ : medals[0].type === 1 ++ ? i18n("Gold") ++ : medals[0].type === 2 ++ ? i18n("Platinum") ++ : i18n("Theme")} +
+ ); + + a + ? literalline + : { +- 123: 12, +- } +- ? line +- : softline; ++ 123: 12, ++ } ++ ? line ++ : softline; + + const config = { + onFailure: +@@ -110,8 +110,8 @@ + typeof error === "string" + ? error + : error && error.message +- ? error.message +- : undefined, ++ ? error.message ++ : undefined, + }, + ); + refresh(); +@@ -131,9 +131,9 @@ + children && !isEmptyChildren(children) + ? children + : props.match +- ? component +- ? React.createElement(component, props) +- : render +- ? render(props) +- : null +- : null; ++ ? component ++ ? React.createElement(component, props) ++ : render ++ ? render(props) ++ : null ++ : null; +``` + +# Output + +```js +let icecream = + what == "cone" + ? (p) => (!!p ? `here's your ${p} cone` : `just the empty cone for you`) + : (p) => `here's your ${p} ${what}`; + +const value = condition1 + ? value1 + : condition2 + ? value2 + : condition3 + ? value3 + : value4; + +const StorybookLoader = ({ match }) => + match.params.storyId === "button" ? ( + + ) : match.params.storyId === "color" ? ( + + ) : match.params.storyId === "typography" ? ( + + ) : match.params.storyId === "loading" ? ( + + ) : match.params.storyId === "deal-list" ? ( + + ) : ( + + {"Missing story book"} + + + + + ); + +const message = + i % 3 === 0 && i % 5 === 0 + ? "fizzbuzz" + : i % 3 === 0 + ? "fizz" + : i % 5 === 0 + ? "buzz" + : String(i); + +const paymentMessage = + 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 paymentMessage2 = + state == "success" + ? 1 //'Payment completed successfully' + : state == "processing" + ? 2 //'Payment processing' + : state == "invalid_cvc" + ? 3 //'There was an issue with your CVC number' + : true //state == 'invalid_expiry' + ? 4 //'Expiry must be sometime in the past.' + : 5; // 'There was an issue with the payment. Please contact support.' + +const foo = ( +
+ {medals[0].record + ? i18n("Record") + : medals[0].unique + ? i18n("Unique") + : medals[0].type === 0 + ? i18n("Silver") + : medals[0].type === 1 + ? i18n("Gold") + : medals[0].type === 2 + ? i18n("Platinum") + : i18n("Theme")} +
+); + +a + ? literalline + : { + 123: 12, + } + ? 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, + }, +); + +const result = + children && !isEmptyChildren(children) + ? children + : props.match + ? component + ? React.createElement(component, props) + : render + ? render(props) + : null + : null; +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.prettier-snap index cf2dee5f0a6a..90755f4af4bd 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.prettier-snap @@ -9,10 +9,10 @@ function getEncoder(encoding) { encoding === "utf8" ? new UTF8Encoder() : encoding === "utf16le" - ? new UTF16Encoder(false) - : encoding === "utf16be" - ? new UTF16Encoder(true) - : throw new Error("Unsupported encoding"); + ? new UTF16Encoder(false) + : encoding === "utf16be" + ? new UTF16Encoder(true) + : throw new Error("Unsupported encoding"); } class Product { diff --git a/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.snap b/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.snap index 3867474eef04..63e384353ff2 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/js/throw_expressions/throw_expression.js.snap @@ -49,10 +49,10 @@ class Product { - encoding === "utf8" - ? new UTF8Encoder() - : encoding === "utf16le" -- ? new UTF16Encoder(false) -- : encoding === "utf16be" -- ? new UTF16Encoder(true) -- : throw new Error("Unsupported encoding"); +- ? new UTF16Encoder(false) +- : encoding === "utf16be" +- ? new UTF16Encoder(true) +- : throw new Error("Unsupported encoding"); + const encoder = encoding === "utf8" ? new UTF8Encoder() + : encoding === "utf16le" ? new UTF16Encoder(false) + : encoding === "utf16be" ? new UTF16Encoder(true) diff --git a/crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.prettier-snap index 7c554dad8f1d..1f16061ac2e2 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.prettier-snap @@ -95,8 +95,8 @@ jsxModeFromElementBreaking ? ( {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo ? "a" : b - ? "b" - : "c"} + ? "b" + : "c"}
; // This chain of ConditionalExpressions prints in JSX mode because there is a diff --git a/crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.snap b/crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.snap new file mode 100644 index 000000000000..72ca40c24020 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/jsx/jsx/conditional-expression.js.snap @@ -0,0 +1,350 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: jsx/jsx/conditional-expression.js +--- + +# Input + +```js +// There are two ways to print ConditionalExpressions: "normal mode" and +// "JSX mode". This is normal mode (when breaking): +// +// test +// ? consequent +// : alternate; +// +// And this is JSX mode (when breaking): +// +// test ? ( +// consequent +// ) : ( +// alternate +// ); +// +// When non-breaking, they look the same: +// +// test ? consequent : alternate; +// +// We only print a conditional expression in JSX mode if its test, +// consequent, or alternate are JSXElements. +// Otherwise, we print in normal mode. + +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// The line does not break. +normalModeNonBreaking ? "a" : "b"; + +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// Its consequent is very long, so it breaks out to multiple lines. +normalModeBreaking + ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa + : "c"; + +// This ConditionalExpression prints in JSX mode because its test is a +// JSXElement. It is non-breaking. +// Note: I have never, ever seen someone use a JSXElement as the test in a +// ConditionalExpression. But this test is included for completeness. +
? jsxModeFromElementNonBreaking : "a"; + +// This ConditionalExpression prints in JSX mode because its consequent is a +// JSXElement. It is non-breaking. +jsxModeFromElementNonBreaking ?
: "a"; + +// This ConditionalExpression prints in JSX mode because its alternate is a +// JSXElement. It is non-breaking. +jsxModeFromElementNonBreaking ? "a" :
; + +// This ConditionalExpression prints in JSX mode because its test is a +// JSXElement. It is breaking. +// Note: I have never, ever seen someone use a JSXElement as the test in a +// ConditionalExpression. But this test is included for completeness. +
+ thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo +
? ( + "jsx mode from element breaking" +) : ( + "a" +); + +// This ConditionalExpression prints in JSX mode because its consequent is a +// JSXElement. It is breaking. +jsxModeFromElementBreaking ? ( +
+ thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo +
+) : ( + "a" +); + +// This ConditionalExpression prints in JSX mode because its alternate is a +// JSXElement. It is breaking. +jsxModeFromElementBreaking ? ( + "a" +) : ( +
+ thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo +
+); + +// This chain of ConditionalExpressions prints in JSX mode because the parent of +// the outermost ConditionalExpression is a JSXExpressionContainer. It is +// 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"; + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain (in this case, at the end). It is +// breaking; notice the consequents and alternates in the entire chain get +// wrapped in parens. +cable ? ( + "satellite" +) : isPublic ? ( + "affairs" +) : network ? ( +
+ thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo +
+) : "dunno"; + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain (in this case, at the beginning). It is +// breaking; notice the consequents and alternates in the entire chain get +// wrapped in parens. +cable ? ( +
+ thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo +
+) : sateline ? ( + "public" +) : affairs ? ( + "network" +) : "dunno"; + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain. It is breaking; notice the consequents +// and alternates in the entire chain get wrapped in parens. +
+ {properties.length > 1 || + (properties.length === 1 && properties[0].apps.size > 1) ? ( + draggingApp == null || newPropertyName == null ? ( + + ) : ( + + ) + ) : null} +
; + +// #3552 +foo ? loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong jsx : +undefined + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -95,8 +95,8 @@ + {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + ? "a" + : b +- ? "b" +- : "c"} ++ ? "b" ++ : "c"} +
; + + // This chain of ConditionalExpressions prints in JSX mode because there is a +``` + +# Output + +```js +// There are two ways to print ConditionalExpressions: "normal mode" and +// "JSX mode". This is normal mode (when breaking): +// +// test +// ? consequent +// : alternate; +// +// And this is JSX mode (when breaking): +// +// test ? ( +// consequent +// ) : ( +// alternate +// ); +// +// When non-breaking, they look the same: +// +// test ? consequent : alternate; +// +// We only print a conditional expression in JSX mode if its test, +// consequent, or alternate are JSXElements. +// Otherwise, we print in normal mode. + +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// The line does not break. +normalModeNonBreaking ? "a" : "b"; + +// This ConditionalExpression has no JSXElements so it prints in normal mode. +// Its consequent is very long, so it breaks out to multiple lines. +normalModeBreaking + ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa + : "c"; + +// This ConditionalExpression prints in JSX mode because its test is a +// JSXElement. It is non-breaking. +// Note: I have never, ever seen someone use a JSXElement as the test in a +// ConditionalExpression. But this test is included for completeness. +
? jsxModeFromElementNonBreaking : "a"; + +// This ConditionalExpression prints in JSX mode because its consequent is a +// JSXElement. It is non-breaking. +jsxModeFromElementNonBreaking ?
: "a"; + +// This ConditionalExpression prints in JSX mode because its alternate is a +// JSXElement. It is non-breaking. +jsxModeFromElementNonBreaking ? "a" :
; + +// This ConditionalExpression prints in JSX mode because its test is a +// JSXElement. It is breaking. +// Note: I have never, ever seen someone use a JSXElement as the test in a +// ConditionalExpression. But this test is included for completeness. +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
? ( + "jsx mode from element breaking" +) : ( + "a" +); + +// This ConditionalExpression prints in JSX mode because its consequent is a +// JSXElement. It is breaking. +jsxModeFromElementBreaking ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+) : ( + "a" +); + +// This ConditionalExpression prints in JSX mode because its alternate is a +// JSXElement. It is breaking. +jsxModeFromElementBreaking ? ( + "a" +) : ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+); + +// This chain of ConditionalExpressions prints in JSX mode because the parent of +// the outermost ConditionalExpression is a JSXExpressionContainer. It is +// 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"; + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain (in this case, at the end). It is +// breaking; notice the consequents and alternates in the entire chain get +// wrapped in parens. +cable ? ( + "satellite" +) : isPublic ? ( + "affairs" +) : network ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+) : ( + "dunno" +); + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain (in this case, at the beginning). It is +// breaking; notice the consequents and alternates in the entire chain get +// wrapped in parens. +cable ? ( +
+ + thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + +
+) : sateline ? ( + "public" +) : affairs ? ( + "network" +) : ( + "dunno" +); + +// This chain of ConditionalExpressions prints in JSX mode because there is a +// JSX element somewhere in the chain. It is breaking; notice the consequents +// and alternates in the entire chain get wrapped in parens. +
+ {properties.length > 1 || + (properties.length === 1 && properties[0].apps.size > 1) ? ( + draggingApp == null || newPropertyName == null ? ( + + ) : ( + + ) + ) : null} +
; + +// #3552 +foo ? ( + + loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong jsx + +) : undefined; +``` + +# Lines exceeding max width of 80 characters +``` + 31: ? johnJacobJingleHeimerSchmidtHisNameIsMyNameTooWheneverWeGoOutThePeopleAlwaysShoutThereGoesJohnJacobJingleHeimerSchmidtYaDaDaDaDaDaDa + 54: thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + 67: thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + 81: thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + 95: {thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + 117: thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo + 131: thisIsASongAboutYourPoorSickPenguinHeHasAFeverAndHisToesAreBlueButIfISingToYourPoorSickPenguinHeWillFeelBetterInADayOrTwo +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.prettier-snap index 89265cf38251..abdb2ed74da4 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.prettier-snap @@ -1,4 +1,4 @@ // expression statemnt of "as" expression hardly ever makes sense, but it's still valid. const [type, x] = [0, 0]; -type as unknown; +(type) as unknown; x as unknown; diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.snap index 7a7dd34f2b09..bffa92e318a8 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/as/expression-statement.ts.snap @@ -24,7 +24,7 @@ x as unknown; @@ -1,4 +1,6 @@ // expression statemnt of "as" expression hardly ever makes sense, but it's still valid. const [type, x] = [0, 0]; --type as unknown; +-(type) as unknown; +// FIXME +// TODO: parse issue +// (type) as unknown; diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.prettier-snap index 1a7817a7ab12..fb8f631dcf72 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.prettier-snap @@ -1,4 +1,6 @@ class A { - constructor(private readonly paramProp: Type) // comment - {} + constructor( + private readonly paramProp: Type, + // comment + ) {} } diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.snap deleted file mode 100644 index 65d450a58a37..000000000000 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/comments/ts-parameter-proerty.ts.snap +++ /dev/null @@ -1,47 +0,0 @@ ---- -source: crates/biome_formatter_test/src/snapshot_builder.rs -info: typescript/comments/ts-parameter-proerty.ts ---- - -# Input - -```ts -class A { - constructor( - private readonly paramProp: Type, - // comment - ) { - } -} - -``` - - -# Prettier differences - -```diff ---- Prettier -+++ Biome -@@ -1,4 +1,6 @@ - class A { -- constructor(private readonly paramProp: Type) // comment -- {} -+ constructor( -+ private readonly paramProp: Type, -+ // comment -+ ) {} - } -``` - -# Output - -```ts -class A { - constructor( - private readonly paramProp: Type, - // comment - ) {} -} -``` - - diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.prettier-snap index dd098c8b9c48..1afc73b7eeb4 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.prettier-snap @@ -27,11 +27,11 @@ type T = test extends B */ foo : test extends B - ? /* comment + ? /* comment comment comment */ - foo - : bar; + foo + : bar; type T = test extends B ? /* comment */ foo : bar; @@ -51,13 +51,13 @@ type T = test extends B comment comment */ - test extends B - ? foo - : /* comment + test extends B + ? foo + : /* comment comment comment */ - bar; + bar; type T = test extends B ? foo : /* comment */ bar; diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.snap new file mode 100644 index 000000000000..8c105ddc6d8a --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/comments.ts.snap @@ -0,0 +1,198 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: typescript/conditional-types/comments.ts +--- + +# Input + +```ts +type A = B extends T + ? // comment + foo + : bar; + +type A = B extends test /* comment + comment + comment +*/ + ? foo + : bar; + +type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : bar; + +type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : test extends B + ? /* comment + comment + comment */ + foo + : bar; + +type T = test extends B + ? /* comment */ + foo + : bar; + +type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ + bar; + +type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ + test extends B + ? foo + : /* comment + comment + comment + */ + bar; + +type T = test extends B + ? foo + : /* comment */ + bar; + +type T = test extends B ? test extends B /* c +c */? foo : bar : bar; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -27,11 +27,11 @@ + */ + foo + : test extends B +- ? /* comment ++ ? /* comment + comment + comment */ +- foo +- : bar; ++ foo ++ : bar; + + type T = test extends B ? /* comment */ foo : bar; + +@@ -51,13 +51,13 @@ + comment + comment + */ +- test extends B +- ? foo +- : /* comment ++ test extends B ++ ? foo ++ : /* comment + comment + comment + */ +- bar; ++ bar; + + type T = test extends B ? foo : /* comment */ bar; + +``` + +# Output + +```ts +type A = B extends T + ? // comment + foo + : bar; + +type A = B extends test /* comment + comment + comment +*/ + ? foo + : bar; + +type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : bar; + +type T = test extends B + ? /* comment + comment + comment + comment + */ + foo + : test extends B + ? /* comment + comment + comment */ + foo + : bar; + +type T = test extends B ? /* comment */ foo : bar; + +type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ + bar; + +type T = test extends B + ? foo + : /* comment + comment + comment + comment + */ + test extends B + ? foo + : /* comment + comment + comment + */ + bar; + +type T = test extends B ? foo : /* comment */ bar; + +type T = test extends B + ? test extends B /* c +c */ + ? foo + : bar + : bar; +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.prettier-snap index 043aba003064..0a9a3c59ff96 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.prettier-snap @@ -1,8 +1,8 @@ export type DeepReadonly = T extends any[] ? DeepReadonlyArray : T extends object - ? DeepReadonlyObject - : T; + ? DeepReadonlyObject + : T; type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K; @@ -17,14 +17,14 @@ type DeepReadonlyObject = { type TypeName = T extends string ? "string" : T extends number - ? "number" - : T extends boolean - ? "boolean" - : T extends undefined - ? "undefined" - : T extends Function - ? "function" - : "object"; + ? "number" + : T extends boolean + ? "boolean" + : T extends undefined + ? "undefined" + : T extends Function + ? "function" + : "object"; type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; type Type02 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap new file mode 100644 index 000000000000..ba82790d6dfd --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/conditonal-types.ts.snap @@ -0,0 +1,141 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: typescript/conditional-types/conditonal-types.ts +--- + +# Input + +```ts +export type DeepReadonly = T extends any[] ? DeepReadonlyArray : T extends object ? DeepReadonlyObject : T; + +type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; + +interface DeepReadonlyArray extends ReadonlyArray> {} + +type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; +}; + +type TypeName = + T extends string ? "string" : + T extends number ? "number" : + T extends boolean ? "boolean" : + T extends undefined ? "undefined" : + T extends Function ? "function" : + "object"; + +type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; +type Type02 = 0 extends ((1 extends 2 ? 3 : 4)) ? 5 : 6; +type Type03 = 0 extends (((1 extends 2 ? 3 : 4))) ? 5 : 6; +type Type04 = 0 extends ((((1 extends 2 ? 3 : 4)))) ? 5 : 6; +type Type05 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; +type Type06 = ((0 extends 1 ? 2 : 3)) extends 4 ? 5 : 6; +type Type07 = (((0 extends 1 ? 2 : 3))) extends 4 ? 5 : 6; +type Type08 = ((((0 extends 1 ? 2 : 3)))) extends 4 ? 5 : 6; + +type T1 = () => void extends T ? U : V; +type T1a = () => (void extends T ? U : V); +type T1b = () => (void) extends T ? U : V; +type T2 = (() => void) extends T ? U : V; + +type U1 = new () => X extends T ? U : V; +type U1a = new () => (X extends T ? U : V); +type U1b = new () => (X) extends T ? U : V; +type U2 = (new () => X) extends T ? U : V; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -1,8 +1,8 @@ + export type DeepReadonly = T extends any[] + ? DeepReadonlyArray + : T extends object +- ? DeepReadonlyObject +- : T; ++ ? DeepReadonlyObject ++ : T; + + type NonFunctionPropertyNames = { + [K in keyof T]: T[K] extends Function ? never : K; +@@ -17,14 +17,14 @@ + type TypeName = T extends string + ? "string" + : T extends number +- ? "number" +- : T extends boolean +- ? "boolean" +- : T extends undefined +- ? "undefined" +- : T extends Function +- ? "function" +- : "object"; ++ ? "number" ++ : T extends boolean ++ ? "boolean" ++ : T extends undefined ++ ? "undefined" ++ : T extends Function ++ ? "function" ++ : "object"; + + type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; + type Type02 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; +``` + +# Output + +```ts +export type DeepReadonly = T extends any[] + ? DeepReadonlyArray + : T extends object + ? DeepReadonlyObject + : T; + +type NonFunctionPropertyNames = { + [K in keyof T]: T[K] extends Function ? never : K; +}[keyof T]; + +interface DeepReadonlyArray extends ReadonlyArray> {} + +type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; +}; + +type TypeName = T extends string + ? "string" + : T extends number + ? "number" + : T extends boolean + ? "boolean" + : T extends undefined + ? "undefined" + : T extends Function + ? "function" + : "object"; + +type Type01 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; +type Type02 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; +type Type03 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; +type Type04 = 0 extends (1 extends 2 ? 3 : 4) ? 5 : 6; +type Type05 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; +type Type06 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; +type Type07 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; +type Type08 = (0 extends 1 ? 2 : 3) extends 4 ? 5 : 6; + +type T1 = () => void extends T ? U : V; +type T1a = () => void extends T ? U : V; +type T1b = () => void extends T ? U : V; +type T2 = (() => void) extends T ? U : V; + +type U1 = new () => X extends T ? U : V; +type U1a = new () => X extends T ? U : V; +type U1b = new () => X extends T ? U : V; +type U2 = (new () => X) extends T ? U : V; +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.prettier-snap index 8d87cb27bf47..ed54fce9e6ab 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.prettier-snap @@ -7,7 +7,7 @@ type TestReturnType any> = T extends ( type Unpacked = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U - ? U - : T extends Promise - ? U - : T; + ? U + : T extends Promise + ? U + : T; diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.snap new file mode 100644 index 000000000000..3c6aca4135b1 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/infer-type.ts.snap @@ -0,0 +1,57 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: typescript/conditional-types/infer-type.ts +--- + +# Input + +```ts +type TestReturnType any> = T extends (...args: any[]) => infer R ? R : any; + +type Unpacked = + T extends (infer U)[] ? U : + T extends (...args: any[]) => infer U ? U : + T extends Promise ? U : + T; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -7,7 +7,7 @@ + type Unpacked = T extends (infer U)[] + ? U + : T extends (...args: any[]) => infer U +- ? U +- : T extends Promise +- ? U +- : T; ++ ? U ++ : T extends Promise ++ ? U ++ : T; +``` + +# Output + +```ts +type TestReturnType any> = T extends ( + ...args: any[] +) => infer R + ? R + : any; + +type Unpacked = T extends (infer U)[] + ? U + : T extends (...args: any[]) => infer U + ? U + : T extends Promise + ? U + : T; +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.prettier-snap index 243656601b23..48ef0eaf94d9 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.prettier-snap @@ -19,19 +19,19 @@ type KnownKeysWithLongExtends = { type TypeName = T extends string ? "string" : T extends number - ? "number" - : T extends boolean - ? "boolean" - : T extends undefined - ? "undefined" - : T extends Function - ? "function" - : "object"; + ? "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; + ? SomeReallyLongThingThatBreaksTheLine + : T extends Promise + ? U + : T; diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.snap new file mode 100644 index 000000000000..2149d3fa496d --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/conditional-types/new-ternary-spec.ts.snap @@ -0,0 +1,134 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: typescript/conditional-types/new-ternary-spec.ts +--- + +# Input + +```ts +// 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; +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -19,19 +19,19 @@ + type TypeName = T extends string + ? "string" + : T extends number +- ? "number" +- : T extends boolean +- ? "boolean" +- : T extends undefined +- ? "undefined" +- : T extends Function +- ? "function" +- : "object"; ++ ? "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; ++ ? SomeReallyLongThingThatBreaksTheLine ++ : T extends Promise ++ ? U ++ : T; +``` + +# Output + +```ts +// 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; +``` + +# Lines exceeding max width of 80 characters +``` + 1: // TypeScript has the same behavior, including a line break after =, but no parens around "conditional": +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.prettier-snap index 7e2f479ee305..5e87077b566c 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.prettier-snap @@ -2,7 +2,7 @@ export type UnwrappedResultRow = { [P in keyof T]: T[P] extends Req ? a : T[P] extends Opt - ? b - : // TEST - never; + ? b + : // TEST + never; }; diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap new file mode 100644 index 000000000000..16281be7eaf4 --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/keyword-types/conditional-types.ts.snap @@ -0,0 +1,58 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: typescript/keyword-types/conditional-types.ts +--- + +# Input + +```ts +export type UnwrappedResultRow = { + [P in keyof T]: ( + T[P] extends Req ? ( + a + ) : ( + T[P] extends Opt ? ( + b + ) : ( + // TEST + never + ) + ) + ); +}; + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -2,7 +2,7 @@ + [P in keyof T]: T[P] extends Req + ? a + : T[P] extends Opt +- ? b +- : // TEST +- never; ++ ? b ++ : // TEST ++ never; + }; +``` + +# Output + +```ts +export type UnwrappedResultRow = { + [P in keyof T]: T[P] extends Req + ? a + : T[P] extends Opt + ? b + : // TEST + never; +}; +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.prettier-snap index 6dd5e905b02a..ee973ca22987 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.prettier-snap @@ -9,18 +9,18 @@ const _ = () => { return 2; default: // exhaustiveness check idiom - type satisfies never; + (type) satisfies never; throw new Error("unreachable"); } }; function needParens() { - let satisfies unknown; - interface satisfies unknown; - module satisfies unknown; - using satisfies unknown; - yield satisfies unknown; - await satisfies unknown; + (let) satisfies unknown; + (interface) satisfies unknown; + (module) satisfies unknown; + (using) satisfies unknown; + (yield) satisfies unknown; + (await) satisfies unknown; } function noNeedParens() { @@ -33,5 +33,5 @@ function noNeedParens() { function satisfiesChain() { satisfies satisfies satisfies satisfies satisfies; - type satisfies never satisfies unknown; + (type) satisfies never satisfies unknown; } diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.snap index 2ab4cd88eccd..ca47a1c0c72f 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/satisfies-operators/expression-statement.ts.snap @@ -53,23 +53,33 @@ satisfies satisfies satisfies satisfies satisfies; ```diff --- Prettier +++ Biome -@@ -15,12 +15,12 @@ +@@ -9,7 +9,7 @@ + return 2; + default: + // exhaustiveness check idiom +- (type) satisfies never; ++ type satisfies never; + throw new Error("unreachable"); + } }; - +@@ -17,8 +17,8 @@ function needParens() { -- let satisfies unknown; -- interface satisfies unknown; -+ (let) satisfies unknown; -+ (interface) satisfies unknown; - module satisfies unknown; - using satisfies unknown; -- yield satisfies unknown; -- await satisfies unknown; -+ (yield) satisfies unknown; -+ (await) satisfies unknown; + (let) satisfies unknown; + (interface) satisfies unknown; +- (module) satisfies unknown; +- (using) satisfies unknown; ++ module satisfies unknown; ++ using satisfies unknown; + (yield) satisfies unknown; + (await) satisfies unknown; } +@@ -33,5 +33,5 @@ - function noNeedParens() { + function satisfiesChain() { + satisfies satisfies satisfies satisfies satisfies; +- (type) satisfies never satisfies unknown; ++ type satisfies never satisfies unknown; + } ``` # Output diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.prettier-snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.prettier-snap index 249bf6862f6a..c9118812ca79 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.prettier-snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.prettier-snap @@ -1,10 +1,10 @@ type Foo = ( | "thing1" // Comment1 - | "thing2" -)[]; // Comment2 // Final comment1 + | "thing2" // Comment2 +)[]; // Final comment1 type Foo = ( | "thing1" // Comment1 - | "thing2" -) & // Comment2 + | "thing2" // Comment2 +) & Bar; // Final comment2 diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap new file mode 100644 index 000000000000..d8d44e3ddd4d --- /dev/null +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/comments.ts.snap @@ -0,0 +1,59 @@ +--- +source: crates/biome_formatter_test/src/snapshot_builder.rs +info: typescript/union/comments.ts +--- + +# Input + +```ts +type Foo = ( + | "thing1" // Comment1 + | "thing2" // Comment2 +)[]; // Final comment1 + +type Foo = ( + | "thing1" // Comment1 + | "thing2" // Comment2 +) & Bar; // Final comment2 + +``` + + +# Prettier differences + +```diff +--- Prettier ++++ Biome +@@ -1,10 +1,10 @@ + type Foo = ( + | "thing1" // Comment1 +- | "thing2" // Comment2 +-)[]; // Final comment1 ++ | "thing2" ++)[]; // Comment2 // Final comment1 + + type Foo = ( + | "thing1" // Comment1 +- | "thing2" // Comment2 +-) & ++ | "thing2" ++) & // Comment2 + Bar; // Final comment2 +``` + +# Output + +```ts +type Foo = ( + | "thing1" // Comment1 + | "thing2" +)[]; // Comment2 // Final comment1 + +type Foo = ( + | "thing1" // Comment1 + | "thing2" +) & // Comment2 + Bar; // Final comment2 +``` + + diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts index 7083f102bd50..b23dd782846b 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts @@ -1,51 +1,51 @@ +type A1 = + | ( + | ( + | ( + | A + // A comment to force break + | B + ) + ) + ); +type A2 = + | ( + | ( + | A + // A comment to force break + | B + ) + | ( + | A + // A comment to force break + | B + ) + ); +type A3 = + | ( | ( + | A + // A comment to force break + | B + ) ); +type A4 = + | ( | ( | ( + | A + // A comment to force break + | B + ) ) ); +type A5 = + | ( + | ( + | { key: string } + | { key: string } + | { key: string } + | { key: string } + ) + | { key: string } + | { key: string } + ); // FIXME -// TODO: we emit invalid AST -// type A1 = -// | ( -// | ( -// | ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ); -// type A2 = -// | ( -// | ( -// | A -// // A comment to force break -// | B -// ) -// | ( -// | A -// // A comment to force break -// | B -// ) -// ); -// type A3 = -// | ( | ( -// | A -// // A comment to force break -// | B -// ) ); -// type A4 = -// | ( | ( | ( -// | A -// // A comment to force break -// | B -// ) ) ); -// type A5 = -// | ( -// | ( -// | { key: string } -// | { key: string } -// | { key: string } -// | { key: string } -// ) -// | { key: string } -// | { key: string } -// ); +// TODO: reformat issue // type A6 = | ( // /*1*/ | ( // | ( @@ -55,28 +55,28 @@ // ) // ) // ); -// -// type B1 = -// | ( -// & ( -// ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ); -// type B2 = -// | ( -// & ( -// | ( -// & ( -// ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ) -// ) -// ); \ No newline at end of file + +type B1 = + | ( + & ( + ( + | A + // A comment to force break + | B + ) + ) + ); +type B2 = + | ( + & ( + | ( + & ( + ( + | A + // A comment to force break + | B + ) + ) + ) + ) + ); \ No newline at end of file diff --git a/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts.snap b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts.snap index 955c782322c7..30deea05bd1a 100644 --- a/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts.snap +++ b/crates/biome_js_formatter/tests/specs/prettier/typescript/union/consistent-with-flow/single-type.ts.snap @@ -6,54 +6,54 @@ info: typescript/union/consistent-with-flow/single-type.ts # Input ```ts +type A1 = + | ( + | ( + | ( + | A + // A comment to force break + | B + ) + ) + ); +type A2 = + | ( + | ( + | A + // A comment to force break + | B + ) + | ( + | A + // A comment to force break + | B + ) + ); +type A3 = + | ( | ( + | A + // A comment to force break + | B + ) ); +type A4 = + | ( | ( | ( + | A + // A comment to force break + | B + ) ) ); +type A5 = + | ( + | ( + | { key: string } + | { key: string } + | { key: string } + | { key: string } + ) + | { key: string } + | { key: string } + ); // FIXME -// TODO: we emit invalid AST -// type A1 = -// | ( -// | ( -// | ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ); -// type A2 = -// | ( -// | ( -// | A -// // A comment to force break -// | B -// ) -// | ( -// | A -// // A comment to force break -// | B -// ) -// ); -// type A3 = -// | ( | ( -// | A -// // A comment to force break -// | B -// ) ); -// type A4 = -// | ( | ( | ( -// | A -// // A comment to force break -// | B -// ) ) ); -// type A5 = -// | ( -// | ( -// | { key: string } -// | { key: string } -// | { key: string } -// | { key: string } -// ) -// | { key: string } -// | { key: string } -// ); +// TODO: reformat issue // type A6 = | ( // /*1*/ | ( // | ( @@ -63,31 +63,31 @@ info: typescript/union/consistent-with-flow/single-type.ts // ) // ) // ); -// -// type B1 = -// | ( -// & ( -// ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ); -// type B2 = -// | ( -// & ( -// | ( -// & ( -// ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ) -// ) -// ); + +type B1 = + | ( + & ( + ( + | A + // A comment to force break + | B + ) + ) + ); +type B2 = + | ( + & ( + | ( + & ( + ( + | A + // A comment to force break + | B + ) + ) + ) + ) + ); ``` @@ -96,96 +96,17 @@ info: typescript/union/consistent-with-flow/single-type.ts ```diff --- Prettier +++ Biome -@@ -1,41 +1,82 @@ --type A1 = -- | A -- // A comment to force break -- | B; --type A2 = -- | ( -- | A -- // A comment to force break -- | B -- ) -- | ( -- | A -- // A comment to force break -- | B -- ); --type A3 = -- | A -- // A comment to force break -- | B; --type A4 = -- | A -- // A comment to force break -- | B; --type A5 = -- | ({ key: string } | { key: string } | { key: string } | { key: string }) -- | { key: string } -- | { key: string }; +@@ -25,11 +25,17 @@ + | ({ key: string } | { key: string } | { key: string } | { key: string }) + | { key: string } + | { key: string }; -type A6 = - /*1*/ - | A - // A comment to force break - | B; -- --type B1 = -- | A -- // A comment to force break -- | B; --type B2 = -- | A -- // A comment to force break -- | B; +// FIXME -+// TODO: we emit invalid AST -+// type A1 = -+// | ( -+// | ( -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ); -+// type A2 = -+// | ( -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// | ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ); -+// type A3 = -+// | ( | ( -+// | A -+// // A comment to force break -+// | B -+// ) ); -+// type A4 = -+// | ( | ( | ( -+// | A -+// // A comment to force break -+// | B -+// ) ) ); -+// type A5 = -+// | ( -+// | ( -+// | { key: string } -+// | { key: string } -+// | { key: string } -+// | { key: string } -+// ) -+// | { key: string } -+// | { key: string } -+// ); ++// TODO: reformat issue +// type A6 = | ( +// /*1*/ | ( +// | ( @@ -195,84 +116,43 @@ info: typescript/union/consistent-with-flow/single-type.ts +// ) +// ) +// ); -+// -+// type B1 = -+// | ( -+// & ( -+// ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ); -+// type B2 = -+// | ( -+// & ( -+// | ( -+// & ( -+// ( -+// | A -+// // A comment to force break -+// | B -+// ) -+// ) -+// ) -+// ) -+// ); + + type B1 = + | A ``` # Output ```ts +type A1 = + | A + // A comment to force break + | B; +type A2 = + | ( + | A + // A comment to force break + | B + ) + | ( + | A + // A comment to force break + | B + ); +type A3 = + | A + // A comment to force break + | B; +type A4 = + | A + // A comment to force break + | B; +type A5 = + | ({ key: string } | { key: string } | { key: string } | { key: string }) + | { key: string } + | { key: string }; // FIXME -// TODO: we emit invalid AST -// type A1 = -// | ( -// | ( -// | ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ); -// type A2 = -// | ( -// | ( -// | A -// // A comment to force break -// | B -// ) -// | ( -// | A -// // A comment to force break -// | B -// ) -// ); -// type A3 = -// | ( | ( -// | A -// // A comment to force break -// | B -// ) ); -// type A4 = -// | ( | ( | ( -// | A -// // A comment to force break -// | B -// ) ) ); -// type A5 = -// | ( -// | ( -// | { key: string } -// | { key: string } -// | { key: string } -// | { key: string } -// ) -// | { key: string } -// | { key: string } -// ); +// TODO: reformat issue // type A6 = | ( // /*1*/ | ( // | ( @@ -282,31 +162,15 @@ info: typescript/union/consistent-with-flow/single-type.ts // ) // ) // ); -// -// type B1 = -// | ( -// & ( -// ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ); -// type B2 = -// | ( -// & ( -// | ( -// & ( -// ( -// | A -// // A comment to force break -// | B -// ) -// ) -// ) -// ) -// ); + +type B1 = + | A + // A comment to force break + | B; +type B2 = + | A + // A comment to force break + | B; ```