I've been stumbled upon this for significant amount of time but not able to do it. My goal is to insert some code inside the Task block under nested scope scenario.
-
I have a function which processes any nested scope which contains Task block and returns a new Task block that contains new code.
-
One of the approach I see is that i traverse this nested scope and collect all the code using an array, when the Task block comes we insert the new Task block inside that array of type CodeBlockItemListSyntax and then convert back to CodeBlockItemSyntax since those are the types I am receiving.
For example
if let _ = newFilter {
for _ in 0...1 {
isCategorySelected = false
Task {
await fetchDataAsync {
print("Nested Async called")
}
}
}
}
I have the code above and I want to insert some code like this
if let _ = newFilter {
for _ in 0...1 {
isCategorySelected = false
Task {
// newly added code here
await fetchDataAsync {
print("Nested Async called")
}
}
}
}
Below is some code for reference
private func performTaskInsertionIntoParentBlock(inputStatement: CodeBlockItemSyntax) /*-> CodeBlockItemSyntax */{
// Create an array to hold the updated statements
var updatedStatements = CodeBlockItemListSyntax { }
// Iterate through each child of the input statement (parent block)
for child in inputStatement.children(viewMode: .sourceAccurate) {
// // Check if the current child contains a Task expression
if let taskExpr = findTaskExpr(in: child) {
// Get the mutated Task block with timer code inserted
if let changedTaskCode = handleNestedTaskInsertion(taskBlock: taskExpr) {
// Append the mutated Task code to updatedStatements
let mutatedStatement = CodeBlockItemSyntax(item: .expr(ExprSyntax(changedTaskCode)))
updatedStatements.append(mutatedStatement)
} else {
// If mutation fails, append the original child (safety fallback)
if let originalStatement = child.as(CodeBlockItemSyntax.self) {
updatedStatements.append(originalStatement)
}
}
} else {
// If it's not a Task expression, retain the original statement
if let originalStatement = child.as(CodeBlockItemSyntax.self) {
updatedStatements.append(originalStatement)
}
}
}
// Create a new CodeBlockSyntax with the updated statements
let modifiedCodeBlock = CodeBlockSyntax {
for statement in updatedStatements {
statement
}
}
// Return the modified parent block with all the statements (including mutated Task blocks)
// return CodeBlockItemSyntax(item: .codeBlock(modifiedCodeBlock))
}
This method will return the new Task Block.
private func handleNestedTaskInsertion(taskBlock: FunctionCallExprSyntax) -> FunctionCallExprSyntax? {
if let taskClosure = taskBlock.trailingClosure {
let timerInsertedTaskCode = insertNewCode(taskClosure)
let modifiedTaskCode = taskBlock.with(\.trailingClosure, timerInsertedTaskCode)
return modifiedTaskCode
}
return nil
}
Below is a logic which finds Task blocks in nested scope
// Helper function to recursively find Task in a given Syntax node
private func findTaskExpr(in syntax: Syntax) -> FunctionCallExprSyntax? {
// Check if the current node is a Task expression
if let taskCall = syntax.as(FunctionCallExprSyntax.self),
let taskName = taskCall.calledExpression.as(DeclReferenceExprSyntax.self)?.baseName.text,
taskName == "Task" {
return taskCall
}
// Recursively check all children of the current node
for child in syntax.children(viewMode: .sourceAccurate) {
if let foundTaskExpr = findTaskExpr(in: child) {
return foundTaskExpr
}
}
// Return nil if no Task expression is found
return nil
}
It would be very helpful .