-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #97 from cipi1965/codable-implementation
Codable implementation
- Loading branch information
Showing
82 changed files
with
2,720 additions
and
8,215 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
248 changes: 248 additions & 0 deletions
248
Rapier/Sources/RapierCLI/Generators/TelegramBotSDKCodableGenerator.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
import Foundation | ||
import Rapier | ||
|
||
private struct Context { | ||
let directory: String | ||
|
||
var outTypes: String = "" | ||
var outMethods: String = "" | ||
|
||
init(directory: String) { | ||
self.directory = directory | ||
} | ||
} | ||
|
||
class TelegramBotSDKCodableGenerator: CodeGenerator { | ||
required init(directory: String) { | ||
self.context = Context(directory: directory) | ||
} | ||
|
||
func start() throws { | ||
|
||
} | ||
|
||
func beforeGeneratingTypes() throws { | ||
let header = """ | ||
// This file is automatically generated by Rapier | ||
import Foundation | ||
""" | ||
context.outTypes.append(header) | ||
} | ||
|
||
func generateType(name: String, info: TypeInfo) throws { | ||
context.outTypes.append(""" | ||
public class \(name): Codable {\n | ||
""") | ||
var allInitParams: [String] = [] | ||
info.fields.forEach { fieldInfo in | ||
let getterName = makeGetterName(typeName: name, fieldName: fieldInfo.name, fieldType: fieldInfo.type) | ||
if fieldInfo.type == "True" { | ||
allInitParams.append(#""\#(fieldInfo.name)" = true"#) | ||
} else { | ||
if let field = buildFieldTemplate(fieldName: getterName, fieldInfo: fieldInfo) { | ||
context.outTypes.append(field) | ||
} | ||
} | ||
|
||
} | ||
var initParamsString = allInitParams.joined(separator: ", ") | ||
if initParamsString.isEmpty { | ||
initParamsString = "[:]" | ||
} | ||
|
||
context.outTypes.append(generateTypeInit(typeName: name, fields: info.fields)) | ||
|
||
context.outTypes.append(""" | ||
}\n\n\n | ||
""") | ||
} | ||
|
||
func generateTypeInit(typeName: String, fields: [FieldInfo]) -> String { | ||
let initParameters = fields.map { (fieldInfo) -> String in | ||
let name = makeGetterName(typeName: typeName, fieldName: fieldInfo.name, fieldType: fieldInfo.type) | ||
var type = fieldInfo.type | ||
|
||
if fieldInfo.isArray { | ||
type = "[\(type)]" | ||
} | ||
|
||
if fieldInfo.isArrayOfArray { | ||
type = "[\(type)]" | ||
} | ||
|
||
if fieldInfo.isOptional { | ||
type = "\(type)? = nil" | ||
} | ||
|
||
return "\(name.camelized()): \(type)" | ||
}.joined(separator: ", ") | ||
|
||
var initString = "" | ||
initString.append(""" | ||
public init(\(initParameters)) {\n | ||
""") | ||
|
||
for field in fields { | ||
let name = field.name.camelized() | ||
initString.append(" self.\(name) = \(name)\n") | ||
} | ||
|
||
initString.append(" }\n\n") | ||
|
||
return initString | ||
} | ||
|
||
func afterGeneratingTypes() throws { | ||
} | ||
|
||
func beforeGeneratingMethods() throws { | ||
let methodsHeader = """ | ||
// This file is automatically generated by Rapier | ||
import Foundation | ||
import Dispatch | ||
public extension TelegramBot { | ||
""" | ||
|
||
context.outMethods.append(methodsHeader) | ||
} | ||
|
||
func generateMethod(name: String, info: MethodInfo) throws { | ||
|
||
let parameters = info.parameters | ||
|
||
let fields: [String] = parameters.map { fieldInfo in | ||
var result = "\(fieldInfo.name.camelized()): \(buildSwiftType(fieldInfo: fieldInfo))" | ||
if fieldInfo.isOptional { | ||
result.append(" = nil") | ||
} | ||
|
||
return result | ||
} | ||
|
||
let arrayFields: [String] = parameters.map { fieldInfo in | ||
return #""\#(fieldInfo.name)": \#(fieldInfo.name.camelized())"# | ||
} | ||
|
||
var fieldsString = fields.joined(separator: ",\n ") | ||
var arrayFieldsString = arrayFields.joined(separator: ",\n") | ||
|
||
let completionName = (name.first?.uppercased() ?? "") + name.dropFirst() + "Completion" | ||
let resultSwiftType = buildSwiftType(fieldInfo: info.result) | ||
|
||
if !fieldsString.isEmpty { | ||
fieldsString.append(",") | ||
} | ||
|
||
if arrayFieldsString.isEmpty { | ||
arrayFieldsString = ":" | ||
} | ||
|
||
let method = """ | ||
typealias \(completionName) = (_ result: \(resultSwiftType), _ error: DataTaskError?) -> () | ||
@discardableResult | ||
func \(name)Sync( | ||
\(fieldsString) | ||
_ parameters: [String: Encodable?] = [:]) -> \(resultSwiftType) { | ||
return requestSync("\(name)", defaultParameters["\(name)"], parameters, [ | ||
\(arrayFieldsString)]) | ||
} | ||
func \(name)Async( | ||
\(fieldsString) | ||
_ parameters: [String: Encodable?] = [:], | ||
queue: DispatchQueue = .main, | ||
completion: \(completionName)? = nil) { | ||
return requestAsync("\(name)", defaultParameters["\(name)"], parameters, [ | ||
\(arrayFieldsString)], | ||
queue: queue, completion: completion) | ||
} | ||
""" | ||
|
||
context.outMethods.append(method) | ||
} | ||
|
||
func afterGeneratingMethods() throws { | ||
context.outMethods.append("\n}\n") | ||
} | ||
|
||
func finish() throws { | ||
try saveTypes() | ||
try saveMethods() | ||
} | ||
|
||
private func saveTypes() throws { | ||
let dir = URL(fileURLWithPath: context.directory, isDirectory: true) | ||
let file = dir.appendingPathComponent("Types.swift", isDirectory: false) | ||
try context.outTypes.write(to: file, atomically: true, encoding: .utf8) | ||
} | ||
|
||
private func saveMethods() throws { | ||
let dir = URL(fileURLWithPath: context.directory, isDirectory: true) | ||
let file = dir.appendingPathComponent("Methods.swift", isDirectory: false) | ||
try context.outMethods.write(to: file, atomically: true, encoding: .utf8) | ||
} | ||
|
||
private func buildSwiftType(fieldInfo: FieldInfo) -> String { | ||
var type: String | ||
if (fieldInfo.isArray) { | ||
type = "[\(fieldInfo.type)]" | ||
} else { | ||
type = fieldInfo.type | ||
} | ||
if (fieldInfo.isOptional) { | ||
type.append("?") | ||
} | ||
return type | ||
} | ||
|
||
private func buildFieldTemplate(fieldName: String, fieldInfo: FieldInfo) -> String? { | ||
let type = fieldInfo.type | ||
let isOptional = fieldInfo.isOptional | ||
let name = fieldName.camelized() | ||
|
||
if fieldInfo.isArrayOfArray { | ||
return """ | ||
public var \(name): [[\(type)]]\(isOptional ? "?" : "") = [[]]\n | ||
""" | ||
} else if fieldInfo.isArray { | ||
return """ | ||
public var \(name): [\(type)]\(isOptional ? "?" : "") = []\n | ||
""" | ||
} else { | ||
return """ | ||
public var \(name): \(type)\(isOptional ? "?" : "")\n | ||
""" | ||
} | ||
} | ||
|
||
private var context: Context | ||
} | ||
|
||
extension TelegramBotSDKCodableGenerator { | ||
private func makeGetterName(typeName: String, fieldName: String, fieldType: String) -> String { | ||
return fieldName | ||
} | ||
} | ||
|
||
extension String { | ||
fileprivate func camelized() -> String { | ||
let components = self.components(separatedBy: "_") | ||
|
||
let firstLowercasedWord = components.first?.lowercased() | ||
|
||
let remainingWords = components.dropFirst().map { | ||
$0.prefix(1).uppercased() + $0.dropFirst().lowercased() | ||
} | ||
return ([firstLowercasedWord].compactMap{ $0 } + remainingWords).joined() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.