Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -3952,6 +3952,12 @@ var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3]; f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3}); +**SpacesInJavaScriptUnion** (``Boolean``) :versionbadge:`clang-format 14` + .. code-block:: c++ + + true: false: + let x: A | B; vs. let x: A|B; + **SpacesInLineCommentPrefix** (``SpacesInLineComment``) :versionbadge:`clang-format 14` How many spaces are allowed at the start of a line comment. To disable the maximum set it to ``-1``, apart from that the maximum takes precedence Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -323,6 +323,9 @@ - Option ``AfterOverloadedOperator`` has been added in ``SpaceBeforeParensOptions`` to allow space between overloaded operator and opening parentheses. +- Option ``SpacesInJavaScriptUnion`` has been added to allow spaces around + JavaScript union and intersection type operators. + libclang -------- Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -3614,6 +3614,15 @@ /// \version 14 SpacesInLineComment SpacesInLineCommentPrefix; + // If ``true``, spaces will be inserted before and after the ``|`` of + // a JavaScript/TypeScript union. + /// \code + /// true: false: + /// let x: A | B; vs. let x: A|B; + /// \endcode + /// \version 14 + bool SpacesInJavaScriptUnion; + /// If ``true``, spaces will be inserted after ``(`` and before ``)``. /// \code /// true: false: Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -818,6 +818,7 @@ Style.SpacesInCStyleCastParentheses); IO.mapOptional("SpacesInLineCommentPrefix", Style.SpacesInLineCommentPrefix); + IO.mapOptional("SpacesInJavaScriptUnion", Style.SpacesInJavaScriptUnion); IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses); IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets); IO.mapOptional("SpaceBeforeSquareBrackets", @@ -1221,6 +1222,7 @@ LLVMStyle.SpacesInContainerLiterals = true; LLVMStyle.SpacesInCStyleCastParentheses = false; LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u}; + LLVMStyle.SpacesInJavaScriptUnion = false; LLVMStyle.SpaceAfterCStyleCast = false; LLVMStyle.SpaceAfterLogicalNot = false; LLVMStyle.SpaceAfterTemplateKeyword = true; Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3517,8 +3517,13 @@ return true; if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion)) return false; - if (Left.is(TT_JsTypeOperator) || Right.is(TT_JsTypeOperator)) + if (Left.is(TT_JsTypeOperator) || Right.is(TT_JsTypeOperator)) { + if ((Left.is(TT_JsTypeOperator) && Right.isTypeOrIdentifier()) || + (Left.isTypeOrIdentifier() || Left.is(TT_TemplateCloser)) && + Right.is(TT_JsTypeOperator)) + return Style.SpacesInJavaScriptUnion; return false; + } if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) && Line.First->isOneOf(Keywords.kw_import, tok::kw_export)) return false; Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -18789,6 +18789,7 @@ CHECK_PARSE_BOOL(SpaceInEmptyParentheses); CHECK_PARSE_BOOL(SpacesInContainerLiterals); CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses); + CHECK_PARSE_BOOL(SpacesInJavaScriptUnion); CHECK_PARSE_BOOL(SpaceAfterCStyleCast); CHECK_PARSE_BOOL(SpaceAfterTemplateKeyword); CHECK_PARSE_BOOL(SpaceAfterLogicalNot); Index: clang/unittests/Format/FormatTestJS.cpp =================================================================== --- clang/unittests/Format/FormatTestJS.cpp +++ clang/unittests/Format/FormatTestJS.cpp @@ -1674,6 +1674,31 @@ verifyFormat("export type X = {\n" " a: Foo|Bar;\n" "};"); + + auto Style = getGoogleJSStyleWithColumns(60); + Style.SpacesInJavaScriptUnion = true; + verifyFormat("let x: A | B = A | B;", Style); + verifyFormat("let x?: A | B = A | B;", Style); + verifyFormat("let x: A & B | C = A & B;", Style); + verifyFormat("let x: Foo = new Foo();", Style); + verifyFormat("function(x: A | B): C & D {}", Style); + verifyFormat("function(x: A | B = A | B): C & D {}", Style); + verifyFormat("function x(path: number | string) {}", Style); + verifyFormat("function x(): string | number {}", Style); + verifyFormat("type Foo = Bar | Baz;", Style); + verifyFormat("type Foo = Bar | Baz;", Style); + verifyFormat("type Foo = (Bar | Baz);", Style); + verifyFormat("let x: Bar | Baz;", Style); + verifyFormat("let x: Bar | Baz;", Style); + verifyFormat("let x: (Foo | Bar)[];", Style); + verifyFormat("type X = {\n" + " a: Foo | Bar;\n" + "};", + Style); + verifyFormat("export type X = {\n" + " a: Foo | Bar;\n" + "};", + Style); } TEST_F(FormatTestJS, UnionIntersectionTypesInObjectType) { @@ -1686,6 +1711,19 @@ " b: b|null,\n" " }) {}\n" "}"); + + auto Style = getGoogleJSStyleWithColumns(60); + Style.SpacesInJavaScriptUnion = true; + verifyFormat("let x: {x: number | null} = {x: number | null};", Style); + verifyFormat("let nested: {x: {y: number | null}};", Style); + verifyFormat("let mixed: {x: [number | null, {w: number}]};", Style); + verifyFormat("class X {\n" + " contructor(x: {\n" + " a: a | null,\n" + " b: b | null,\n" + " }) {}\n" + "}", + Style); } TEST_F(FormatTestJS, ClassDeclarations) {