Add CodegenKit
as dependency of your project.
let package = Package(
...
dependencies: [
.package(url: "https://github.com/omochi/CodegenKit", from: "1.2.2")
]
...
)
Perform command below.
$ swift package codegen-kit init
This is all that is needed to complete the required setup.
Instead of command, you can do it manually. In that case, see instructions described later in this document.
Define placeholders with @codegen
and @end
as follows.
// TSDecl.swift
protocol TSDecl {}
extension TSDecl {
// @codegen(as)
// @end
}
Attach name of placeholder at @codegen
.
The init command created executable target named codegen
.
Add your renderer code into this.
Implement renderers to conform CodegenKit.Renderer
as follows.
import Foundation
import CodegenKit
struct Node {
var stem: String
var typeName: String
}
struct TSDeclRenderer: Renderer {
var nodes: [Node] = [...]
func isTarget(file: URL) -> Bool {
file.lastPathComponent == "TSDecl.swift"
}
func render(template: inout CodeTemplate, file: URL, on runner: CodegenRunner) throws {
template["as"] = asCasts()
}
func asCasts() -> String {
let lines: [String] = nodes.map { (node) in
"""
public var as\(node.stem.pascal): \(node.typeName)? { self as? \(node.typeName) }
"""
}
return lines.joined(separator: "\n")
}
}
Specify target source code for this renderer with isTarget
method.
Write rendering logics into render
method.
Your source code are passwd as CodeTemplate
object,
you can edit content of placeholders via subscript.
CodegenKit automatically format generated code by swift-format. So you don't have to worry about precise textual control like indenting when write renderer.
The init command created main.swift
in codegen
target.
The codegen runner is defined in here.
Edit this source to register your renderer to the runner.
import CodegenKit
let runner = CodegenRunner(renderers: [
TSDeclRenderer()
])
let dir = URL(fileURLWithPath: CommandLine.arguments[1])
try runner.run(directories: [dir])
The init command created codegen
command plugin.
So you can perform code generation as below.
$ swift package codegen
CodegenKit initially creates codegen
executable and plugin by the init command,
but has no requirements for these specifications after that.
So, you can modify these targets source and build more complex code generations.
To setup it manually without using the init command, do the following steps instead.
Create codegen
executable target.
let package = Package(
...
targets: [
.executableTarget(
name: "codegen",
dependencies: [
.product(name: "CodegenKit", package: "CodegenKit")
]
),
...
)
You can use any target name other than codegen
.
Write main file that build CodegenKit.CodegenRunner
and run it.
import CodegenKit
let runner = CodegenRunner(renderers: [
TSDeclRenderer()
])
let dir = URL(fileURLWithPath: CommandLine.arguments[1])
try runner.run(directories: [dir])
There are no specification about anything including command line arguments. Above example build as run on current working directory.
After that, you can generate code as below.
$ swift run codegen .
You can create command plugin
that perform previous codegen
executable.
After that, you can generate code as below.
$ swift package codegen