Skip to content
Merged
4 changes: 2 additions & 2 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ opt_in_rules:
- legacy_random
- literal_expression_end_indentation
- lower_acl_than_parent
# - missing_docs
- missing_docs
- modifier_order
- multiline_arguments
- multiline_arguments_brackets
Expand Down Expand Up @@ -120,7 +120,7 @@ excluded:
- Mint
- Examples
- Macros
- Sources/SyntaxKit/parser
- Sources/SyntaxKit/Parser
indentation_width:
indentation_width: 2
file_name:
Expand Down
24 changes: 24 additions & 0 deletions Examples/Completed/swiftui/code.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
public import SwiftUI


public struct TodoItemRow: View {
private let item: TodoItem
private let onToggle: @MainActor @Sendable (Date) -> Void

public var body: some View {
HStack {
Button(action: onToggle) {
Image(systemName: item.isCompleted ? "checkmark.circle.fill" : "circle")
.foregroundColor(item.isCompleted ? .green : .gray)
}

Button(action: {
Task { @MainActor [weak self] in
self?.onToggle(Date())
}
}) {
Image(systemName: "trash")
}
}
}
}
65 changes: 65 additions & 0 deletions Examples/Completed/swiftui/dsl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Import("SwiftUI").access("public")

Struct("TodoItemRow") {
Variable(.let, name: "item", type: "TodoItem").access("private")

Variable(.let, name: "onToggle", type:
ClosureType(returns: "Void"){
ClosureParameter("Date")
}
.attribute("@MainActor")
.attribute("@Sendable")
)
.access("private")

ComputedProperty("body", type: "some View") {
Init("HStack") {
ParameterExp(unlabeled: Closure{
ParameterExp(unlabeled: Closure{
Init("Button") {
ParameterExp(name: "action", value: VariableExp("onToggle"))
ParameterExp(unlabeled: Closure{
Init("Image") {
ParameterExp(name: "systemName", value: ConditionalOp(
if: VariableExp("item").property(name: "isCompleted"),
then: Literal.string("checkmark.circle.fill"),
else: Literal.string("circle")
))
}.call("foregroundColor"){
ParameterExp(unlabeled: ConditionalOp(
if: VariableExp("item").property(name: "isCompleted"),
then: EnumCase("green"),
else: EnumCase("gray")
))
}
})
}
Init("Button") {
ParameterExp(name: "action", value: Closure {
Init("Task") {
ParameterExp(unlabeled: Closure(
capture: {
ParameterExp(unlabeled: VariableExp("self").reference("weak"))
},
body: {
VariableExp("self").optional().call("onToggle") {
ParameterExp(unlabeled: Init("Date"))
}
}
).attribute("@MainActor"))
}
})
ParameterExp(unlabeled: Closure {
Init("Image") {
ParameterExp(name: "systemName", value: Literal.string("trash"))
}
})
}
})
})

}
}
}
.inherits("View")
.access("public")
1 change: 1 addition & 0 deletions Examples/Completed/swiftui/syntax.json

Large diffs are not rendered by default.

103 changes: 0 additions & 103 deletions Examples/Remaining/swiftui/code.swift

This file was deleted.

58 changes: 0 additions & 58 deletions Line.swift

This file was deleted.

2 changes: 1 addition & 1 deletion Sources/SyntaxKit/CodeBlocks/CommentedCodeBlock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ internal struct CommentedCodeBlock: CodeBlock {
let newFirstToken = firstToken.with(\.leadingTrivia, commentTrivia + firstToken.leadingTrivia)

let rewriter = FirstTokenRewriter(newToken: newFirstToken)
let rewritten = rewriter.visit(Syntax(base.syntax))
let rewritten = rewriter.rewrite(Syntax(base.syntax))
return rewritten
}
}
11 changes: 7 additions & 4 deletions Sources/SyntaxKit/ControlFlow/If+Body.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,20 @@
import SwiftSyntax

extension If {
/// Builds the body block for the if statement.
internal func buildBody() -> CodeBlockSyntax {
/// Builds the body of the if expression.
/// - Returns: The code block syntax for the body.
public func buildBody() -> CodeBlockSyntax {
CodeBlockSyntax(
leftBrace: .leftBraceToken(leadingTrivia: .space, trailingTrivia: .newline),
statements: buildBodyStatements(from: body),
rightBrace: .rightBraceToken(leadingTrivia: .newline)
)
}

/// Builds the statements for a code block from an array of CodeBlocks.
internal func buildBodyStatements(from blocks: [CodeBlock]) -> CodeBlockItemListSyntax {
/// Builds the body statements from an array of code blocks.
/// - Parameter blocks: The code blocks to convert to statements.
/// - Returns: The code block item list syntax.
public func buildBodyStatements(from blocks: [CodeBlock]) -> CodeBlockItemListSyntax {
CodeBlockItemListSyntax(
blocks.compactMap { block in
createCodeBlockItem(from: block)?.with(\.trailingTrivia, .newline)
Expand Down
4 changes: 3 additions & 1 deletion Sources/SyntaxKit/ControlFlow/If+CodeBlockItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ import SwiftSyntax

extension If {
/// Creates a code block item from a CodeBlock.
internal func createCodeBlockItem(from block: CodeBlock) -> CodeBlockItemSyntax? {
/// - Parameter block: The code block to convert.
/// - Returns: The code block item syntax or nil if conversion is not possible.
public func createCodeBlockItem(from block: CodeBlock) -> CodeBlockItemSyntax? {
if let enumCase = block as? EnumCase {
// Handle EnumCase specially - use expression syntax for enum cases in expressions
return CodeBlockItemSyntax(item: .expr(enumCase.exprSyntax))
Expand Down
5 changes: 3 additions & 2 deletions Sources/SyntaxKit/ControlFlow/If+Conditions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
import SwiftSyntax

extension If {
/// Builds the condition elements for the if statement.
internal func buildConditions() -> ConditionElementListSyntax {
/// Builds the conditions for the if expression.
/// - Returns: The condition element list syntax.
public func buildConditions() -> ConditionElementListSyntax {
ConditionElementListSyntax(
conditions.enumerated().map { index, block in
let needsComma = index < conditions.count - 1
Expand Down
5 changes: 3 additions & 2 deletions Sources/SyntaxKit/ControlFlow/If+ElseBody.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
import SwiftSyntax

extension If {
/// Builds the else body for the if statement, handling else-if chains.
internal func buildElseBody() -> IfExprSyntax.ElseBody? {
/// Builds the else body for the if expression.
/// - Returns: The else body syntax or nil if no else body exists.
public func buildElseBody() -> IfExprSyntax.ElseBody? {
guard let elseBlocks = elseBody else {
return nil
}
Expand Down
21 changes: 21 additions & 0 deletions Sources/SyntaxKit/Core/CodeBlock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,25 @@
public protocol CodeBlock {
/// The SwiftSyntax representation of the code block.
var syntax: SyntaxProtocol { get }

/// Calls a method on this code block with the given name and parameters.
/// - Parameters:
/// - name: The name of the method to call.
/// - parameters: A closure that returns the parameters for the method call.
/// - Returns: A code block representing the method call.
func call(_ name: String, @ParameterExpBuilderResult _ parameters: () -> [ParameterExp])
-> CodeBlock
}

extension CodeBlock {
/// Calls a method on this code block with the given name and parameters.
/// - Parameters:
/// - name: The name of the method to call.
/// - parameters: A closure that returns the parameters for the method call.
/// - Returns: A code block representing the method call.
public func call(
_ name: String, @ParameterExpBuilderResult _ parameters: () -> [ParameterExp] = { [] }

Check warning on line 54 in Sources/SyntaxKit/Core/CodeBlock.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SyntaxKit/Core/CodeBlock.swift#L54

Added line #L54 was not covered by tests
) -> CodeBlock {
FunctionCallExp(base: self, methodName: name, parameters: parameters())
}
}
Loading
Loading