Skip to content

Commit b2e126f

Browse files
committed
Add appendInterpolation with optional syntax nodes
This commit introduces a new method, appendInterpolation, to the SyntaxStringInterpolation class, which takes an optional syntax node parameter. If the provided node is nil, no interpolation is added. Otherwise, interpolation is performed as usual. Additionally, this new method has been integrated into the CodeGeneration package to eliminate the usage of interpolation. This change simplifies the codebase and provides a more robust approach to handling syntax nodes in string interpolations.
1 parent 39a4239 commit b2e126f

File tree

5 files changed

+48
-7
lines changed

5 files changed

+48
-7
lines changed

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/RawSyntaxNodesFile.swift

+6-5
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,9 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
217217
let list = ExprListSyntax {
218218
ExprSyntax("layout.initialize(repeating: nil)")
219219
for (index, child) in node.children.enumerated() {
220-
let optionalMark = child.isOptional ? "?" : ""
221-
ExprSyntax("layout[\(raw: index)] = \(child.varOrCaseName.backtickedIfNeeded)\(raw: optionalMark).raw")
220+
let optionalMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil
221+
222+
ExprSyntax("layout[\(raw: index)] = \(child.varOrCaseName.backtickedIfNeeded)\(optionalMark).raw")
222223
.with(\.leadingTrivia, .newline)
223224
}
224225
}
@@ -239,12 +240,12 @@ let rawSyntaxNodesFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
239240

240241
for (index, child) in node.children.enumerated() {
241242
try VariableDeclSyntax("public var \(child.varOrCaseName.backtickedIfNeeded): Raw\(child.buildableType.buildable)") {
242-
let iuoMark = child.isOptional ? "" : "!"
243+
let exclamationMark = child.isOptional ? nil : TokenSyntax.exclamationMarkToken()
243244

244245
if child.syntaxNodeKind == .syntax {
245-
ExprSyntax("layoutView.children[\(raw: index)]\(raw: iuoMark)")
246+
ExprSyntax("layoutView.children[\(raw: index)]\(exclamationMark)")
246247
} else {
247-
ExprSyntax("layoutView.children[\(raw: index)].map(\(child.syntaxNodeKind.rawType).init(raw:))\(raw: iuoMark)")
248+
ExprSyntax("layoutView.children[\(raw: index)].map(\(child.syntaxNodeKind.rawType).init(raw:))\(exclamationMark)")
248249
}
249250
}
250251
}

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxNodesFile.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,12 @@ func syntaxNode(emitKind: SyntaxNodeKind) -> SourceFileSyntax {
177177
}
178178
}
179179

180+
let questionMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil
181+
180182
AccessorDeclSyntax(
181183
"""
182184
set(value) {
183-
self = \(node.kind.syntaxType)(data.replacingChild(at: \(raw: index), with: value\(raw: child.isOptional ? "?" : "").data, arena: SyntaxArena()))
185+
self = \(node.kind.syntaxType)(data.replacingChild(at: \(raw: index), with: value\(questionMark).data, arena: SyntaxArena()))
184186
}
185187
"""
186188
)

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxTraitsFile.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ let syntaxTraitsFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
2626
"""
2727
) {
2828
for child in trait.children {
29+
let questionMark = child.isOptional ? TokenSyntax.postfixQuestionMarkToken() : nil
30+
2931
DeclSyntax(
3032
"""
3133
\(child.documentation)
32-
var \(child.varOrCaseName): \(child.syntaxNodeKind.syntaxType)\(raw: child.isOptional ? "?" : "") { get set }
34+
var \(child.varOrCaseName): \(child.syntaxNodeKind.syntaxType)\(questionMark) { get set }
3335
"""
3436
)
3537
}

Sources/SwiftSyntaxBuilder/Syntax+StringInterpolation.swift

+20
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ extension SyntaxStringInterpolation: StringInterpolationProtocol {
6363
}
6464

6565
/// Append a syntax node to the interpolation.
66+
///
67+
/// This method accepts a syntax node and appends it to the interpolation.
68+
/// If there was a previous indentation value, the method will indent the
69+
/// syntax node with that value. If not, it will use the syntax node as-is.
70+
///
71+
/// - Parameter node: A syntax node that conforms to `SyntaxProtocol`.
6672
public mutating func appendInterpolation<Node: SyntaxProtocol>(
6773
_ node: Node
6874
) {
@@ -84,6 +90,20 @@ extension SyntaxStringInterpolation: StringInterpolationProtocol {
8490
self.lastIndentation = nil
8591
}
8692

93+
/// Append an optional syntax node to the interpolation.
94+
///
95+
/// This method accepts an optional syntax node and appends it to the interpolation
96+
/// if it exists. If the syntax node is nil, this method does nothing.
97+
///
98+
/// - Parameter node: An optional syntax node that conforms to `SyntaxProtocol`.
99+
public mutating func appendInterpolation<Node: SyntaxProtocol>(
100+
_ node: Node?
101+
) {
102+
if let node {
103+
appendInterpolation(node)
104+
}
105+
}
106+
87107
public mutating func appendInterpolation<T>(raw value: T) {
88108
sourceText.append(contentsOf: String(describing: value).utf8)
89109
self.lastIndentation = nil

Tests/SwiftSyntaxBuilderTest/StringInterpolationTests.swift

+16
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ final class StringInterpolationTests: XCTestCase {
7272
)
7373
}
7474

75+
func testOptionalInterpolationWithNil() {
76+
let tokenSyntax: TokenSyntax? = nil
77+
78+
let funcSyntax: DeclSyntax = "func foo\(tokenSyntax)()"
79+
XCTAssertTrue(funcSyntax.is(FunctionDeclSyntax.self))
80+
XCTAssertEqual(funcSyntax.description, "func foo()")
81+
}
82+
83+
func testOptionalInterpolationWithValue() {
84+
let tokenSyntax: TokenSyntax? = .identifier("Bar")
85+
86+
let funcSyntax: DeclSyntax = "func foo\(tokenSyntax)()"
87+
XCTAssertTrue(funcSyntax.is(FunctionDeclSyntax.self))
88+
XCTAssertEqual(funcSyntax.description, "func fooBar()")
89+
}
90+
7591
func testPatternInterpolation() {
7692
let letPattern: PatternSyntax = "let x"
7793
XCTAssertTrue(letPattern.is(ValueBindingPatternSyntax.self))

0 commit comments

Comments
 (0)