diff --git a/Sources/SwiftSyntaxBuilder/ResultBuilderExtensions.swift b/Sources/SwiftSyntaxBuilder/ResultBuilderExtensions.swift index cdd7f591342..237dec791a3 100644 --- a/Sources/SwiftSyntaxBuilder/ResultBuilderExtensions.swift +++ b/Sources/SwiftSyntaxBuilder/ResultBuilderExtensions.swift @@ -40,6 +40,18 @@ extension CodeBlockItemListBuilder { public static func buildExpression(_ expression: some Sequence) -> Component { buildExpression(expression.map { CodeBlockItemSyntax(item: .decl(DeclSyntax($0))) }) } + + public static func buildFinalResult(_ component: Component) -> CodeBlockItemListSyntax { + .init( + component.enumerated().map { (index, expression) in + if index > component.startIndex, !expression.leadingTrivia.contains(where: \.isNewline) { + return expression.with(\.leadingTrivia, .newline.merging(expression.leadingTrivia)) + } else { + return expression + } + } + ) + } } extension ConditionElementListBuilder { diff --git a/Sources/SwiftSyntaxMacroExpansion/MacroExpansion.swift b/Sources/SwiftSyntaxMacroExpansion/MacroExpansion.swift index b2f9d6bfa82..b3cd0d25e0a 100644 --- a/Sources/SwiftSyntaxMacroExpansion/MacroExpansion.swift +++ b/Sources/SwiftSyntaxMacroExpansion/MacroExpansion.swift @@ -528,5 +528,15 @@ public func collapse( break } - return expansions.joined(separator: separator) + // Join the expansions ensuring `separator` between them. + var collapsed = "" + for expansion in expansions { + if collapsed.isEmpty || expansion.hasPrefix(separator) { + collapsed.append(expansion) + } else { + collapsed.append(separator + expansion) + } + } + + return collapsed } diff --git a/Tests/SwiftSyntaxBuilderTest/CollectionNodeFlatteningTests.swift b/Tests/SwiftSyntaxBuilderTest/CollectionNodeFlatteningTests.swift index e54c06ac721..a1e9c9a5cda 100644 --- a/Tests/SwiftSyntaxBuilderTest/CollectionNodeFlatteningTests.swift +++ b/Tests/SwiftSyntaxBuilderTest/CollectionNodeFlatteningTests.swift @@ -75,4 +75,31 @@ final class CollectionNodeFlatteningTests: XCTestCase { """ ) } + + func test_FlattenCodeBlockItemListWithCodeBlockInterpolated() { + let block = CodeBlockItemListSyntax { + "let a = 1" + "let b = 2" + "let c = 3" + } + + let buildable = CodeBlockItemListSyntax { + "let one = object.methodOne()" + "let two = object.methodTwo()" + "let three = {\(block)}()" + } + + assertBuildResult( + buildable, + """ + let one = object.methodOne() + let two = object.methodTwo() + let three = { + let a = 1 + let b = 2 + let c = 3 + }() + """ + ) + } }