Sources/MockoloFramework/Templates/ClosureTemplate.swift (58 lines of code) (raw):
//
// Copyright (c) 2018. Uber Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
extension ClosureModel {
func applyClosureTemplate(type: SwiftType,
cast: String?,
name: String,
params: [(String, SwiftType)],
returnDefaultType: SwiftType) -> String {
let handlerParamValsStr = params.map { (argName, argType) -> String in
if argType.isAutoclosure {
return argName.safeName + "()"
}
if argType.isInOut {
return "&" + argName.safeName
}
return argName.safeName
}.joined(separator: ", ")
let handlerReturnDefault = renderReturnDefaultStatement(name: name, type: returnDefaultType)
let prefix = [
throwing.hasError ? String.try + " " : nil,
isAsync ? String.await + " " : nil,
].compactMap { $0 }.joined()
let returnStr = returnDefaultType.isVoid ? "" : "return "
var callAndReturnStmt = "\(returnStr)\(prefix)\(name)(\(handlerParamValsStr))\(cast ?? "")"
/// For when a non-escaping closure argument is passed to the handler function as `Any`
if case .closure(let closure) = type.kind {
for (handlerArgType, (label, type)) in zip(closure.arguments.map(\.type), params) {
guard handlerArgType == .Any && !type.isEscapable else {
continue
}
let prefix = [
closure.throwing.hasError ? String.try + " " : nil,
closure.isAsync ? String.await + " " : nil,
].compactMap { $0 }.joined()
callAndReturnStmt = """
\(returnStr)\(prefix)withoutActuallyEscaping(\(label.safeName)) { \(label.safeName) in
\(callAndReturnStmt.addingIndent(1))
}
"""
}
} else {
assertionFailure("\(type) is not closure?")
}
return """
\(2.tab)if let \(name) = \(name) {
\(callAndReturnStmt.addingIndent(3))
\(2.tab)}
\(2.tab)\(handlerReturnDefault)
"""
}
private func renderReturnDefaultStatement(name: String, type: SwiftType) -> String {
guard !type.isVoid else { return "" }
if let result = type.defaultVal() {
if result.isEmpty {
return ""
}
return "return \(result)"
}
return "\(String.fatalError)(\"\(name) returns can't have a default value thus its handler must be set\")"
}
}