A list of cool DSLs made with Swift 5.1’s @functionBuilder
Currently, you instead have to use
@_functionBuilder
as it is a private implementation. This will change in the future, however.
Feel free to contribute if you make or find something awesome.
-
The proposal has not been fully implemented in the current Xcode betas, which provide a simpler transformation than specified.
-
Projects
A list of helpful guides/tutorials on function builders
- Crash course in Swift's 'function builders' with SwiftUI
- Inside SwiftUI's Declarative Syntax's Compiler Magic
- The Swift 5.1 features that power SwiftUI’s API
- Create Your First Function Builder in 10 Minutes
- DependencyInjection - Dependency injection with function builders and property wrappers
DIContainer.register {
New(MediaPlayer() as MediaplayerProtocol)
New { _, id in ArticleViewModel(id: id) as PageViewModelProtocol }
Shared(Router.init, as: RouterProtocol.self, DeeplinkHandler.self)
}
- Artemis - Interact with GraphQL in Swift - not strings
Operation(.query) {
Add(\.country, alias: "canada") {
Add(\.name)
Add(\.continent) {
Add(\.name)
}
}.code("CA")
}
- graphique - Experimental GraphQL query builders
query("") {
hero {
\.name
lens(\.friends) {
\.name
}
}
}
- Graphiti - Swift GraphQL Schema/Type framework for macOS and Linux
Schema<StarWarsAPI, StarWarsStore> {
Enum(Episode.self) {
Value(.newHope)
.description("Released in 1977.")
Value(.empire)
.description("Released in 1980.")
Value(.jedi)
.description("Released in 1983.")
}
.description("One of the films in the Star Wars Trilogy.")
...
}
- SociableWeaver - Build declarative GraphQL queries in Swift.
Weave(.query) {
Object(Post.self) {
Field(Post.CodingKeys.title)
Object(Post.CodingKeys.author) {
Field(Author.CodingKeys.id)
Field(Author.CodingKeys.name)
.argument(key: "lastName", value: "Doe")
}
Object(Post.CodingKeys.comments) {
Field(Comment.CodingKeys.id)
Field(Comment.CodingKeys.content)
}
.argument(key: "filter", value: CommentFilter.recent)
}
}
- ...
- HTML-DSL - A DSL for writing HTML in Swift
html(lang: "en-US") {
body(customData: ["hello":"world"]) {
article(classes: "readme", "modern") {
h1 {
"Hello World"
}
}
}
}
- Vaux - A HTML DSL library for Swift
html {
body {
link(url: url, label: "Google", inline: true)
}
}
- HyperSwift - A Swift DSL for generating HTML and CSS documents
VStack(justify: .center, align: .center) {
HStack(justify: .spaceEvenly, align: .center) {
Image(url: "/images/error_bomb.png")
.width(100)
.height(100)
Header(.header3) { "HTTP 500" }
.font(weight: "bold", size: 40, family: "SF Mono")
}
Paragraph(fiveOfiveMessage)
}
.backgroundColor(GColors.lightRed)
.textAlign(.center)
.margin(5, .percent)
.display(.flex)
.shadow(x: 20, y: 30, color: GColors.cardShadow)
.border(width: 1, color: .black)
- swift-request - Declarative HTTP networking, designed for SwiftUI
Request {
Url("https://jsonplaceholder.typicode.com/todo")
Header.Accept(.json)
}
.onData { ... }
let myJson = Json {
JsonProperty(key: "firstName", value: "Carson")
}
myJson["firstName"].string // "Carson"
- ...
- NSAttributedStringBuilder - Composing NSAttributedString with SwiftUI-style syntax
NSAttributedString {
AText("Hello world")
.font(.systemFont(ofSize: 24))
.foregroundColor(.red)
LineBreak()
AText("with Swift")
.font(.systemFont(ofSize: 20))
.foregroundColor(.orange)
}
- ...
- Corvus – Building RESTful APIs with a declarative syntax.
var api = Api {
BasicAuthGroup<User>("login") { login }
JWTAuthGroup<User.Payload> {
Group("users") { users }
Group("inventory") {
Group("articles") { articles }
}
}
}
- ...
- MacroApp - A SwiftUI-like, declarative way to setup endpoints for the MacroExpress SwiftNIO based web framework framework
@main
struct HelloWorld: App {
var body: some Endpoints {
Use(logger("dev"), bodyParser.urlencoded())
Route("/admin") {
Get("/view") { req, res, _ in res.render("admin-index.html") }
Render("help", template: "help")
}
Get { req, res, next in
res.render("index.html")
}
}
}
- Meridian - A web server written in Swift that lets you write your endpoints in a declarative way
struct SampleEndpoint: Responder {
@QueryParameter("sort_direction")
var sortDirection: SortDirection = .ascending
@URLParameter(\.id) var userID
@EnivronmentObject var database: Database
func body() throws {
JSON(database.fetchFollowers(of: userID, sortDirection: sortDirection))
}
}
Server(errorRenderer: BasicErrorRenderer()).register {
SampleEndpoint()
.on("/api/users/\(\.id))/followers")
}
.environmentObject(Database())
.listen()
- ControlFlowUI - A library that add control flow functionality to SwitUI, using the power of
@functionBuilder
andViewBuilder
List(dogs.identified(by: \.name)) { dog in
SwitchValue(dog) {
CaseIs(Animal.self) { value in
Text(value.species)
}
CaseIs(Dog.self) { value in
Text(value.breed)
}
}
}
- PathBuilder - Implementation of function builder for SwiftUI Path.
Path {
Move(to: CGPoint(x: 50, y: 50))
Line(to: CGPoint(x: 100, y: 100))
Line(to: CGPoint(x: 0, y: 100))
Close()
}
- SwiftWebUI - A demo implementation of SwiftUI for the Web
VStack {
Text("🥑🍞 #\(counter)")
.padding(.all)
.background(.green, cornerRadius: 12)
.foregroundColor(.white)
.tapAction(self.countUp)
}
- SequenceBuilder - Allows you to build arbitrary heterogenous sequences without loosing information about the underlying types. It is especially useful for building custom container views in SwiftUI.
struct EnumerationView<Content: Sequence>: View where Content.Element: View {
let content: Content
init(@SequenceBuilder builder: () -> Content) {
self.content = builder()
}
var body: some View {
VStack(alignment: .leading, spacing: 8) {
ForEach(sequence: content) { (index, content) in
HStack(alignment: .top) {
Text("\(index + 1). ")
content
}
}
}
}
}
// Usage:
EnumerationView {
Text("Some text")
VStack {
ForEach(0..<10, id: \.self) { _ in
Text("Lorem ipsum dolet.")
}
}
HStack {
Text("With image:")
Image(systemName: "checkmark")
}
}
- SwiftDB - A type-safe, SwiftUI-inspired wrapper around CoreData
// Define an Entity:
struct Foo: Entity, Identifiable {
@Attribute var bar: String = "Untitled"
var id: some Hashable {
bar
}
}
// Define a Schema:
struct MySchema: Schema {
var entities: Entities {
Foo.self
Bar.self
Baz.self
}
}
- ComposableNavigator - The ComposableNavigator is based on the concept of PathBuilder composition in form of a NavigationTree. A NavigationTree composes PathBuilders to describe all valid navigation paths in an application. That also means that all screens in our application are accessible via a pre-defined navigation path.
struct AppNavigationTree: NavigationTree {
let homeViewModel: HomeViewModel
let detailViewModel: DetailViewModel
let settingsViewModel: SettingsViewModel
var builder: some PathBuilder {
Screen(
HomeScreen.self,
content: {
HomeView(viewModel: homeViewModel)
},
nesting: {
DetailScreen.Builder(viewModel: detailViewModel),
SettingsScreen.Builder(viewModel: settingsViewModel)
}
)
}
}
Based on AppNavigationTree
, the following navigation paths are valid:
/home
/home/detail?id=0
/home/settings
More information on the NavigationTree
and how to compose PathBuilder
s can be found here.
- Rorschach - Write Xcode UI Tests BDD style 🤷🏻♂️
expect(in: &context) {
Given {
ILearnABitMore()
IBuildARocket()
}
When {
ILaunchARocket()
}
Then {
ICanSeeTheStars()
}
}
- SwiftValidation – Declarative way to validate our object.
try validate(user) {
validate(\.id).isPositive()
validate(\.email) {
isNotEmpty()
isEmail()
}
}
- BoxLayout - [WIP] SwiftUI's interface like AutoLayout DSL
BoxCenter {
BoxVStack {
BoxElement { toggleView }
BoxEmpty()
.frame(height: 20)
if flag {
BoxElement { top }
.aspectRatio(ratio: CGSize(width: 1, height: 1))
}
}
}
Lego {
ForIn(3...4) { x in
Section(layout:FlowLayout(col: x)) {
ForIn(0...(x + 3)) { y in
ImageItem(value: UIImage(named: "\(y % 2)")!)
}
}
}
}
- Mockingbird - An experiment of implementing a UI layout and rendering framework inspired by SwiftUI
var content: some Node {
VerticalStack {
Repeated(0..<count) {
Button(action: { self.count += 1 }) {
BoxedText()
}
}
}
.cornerRadius(20)
.animation(.spring)
}
- TurtleBuilder - Turtle graphics made on the top of Swift's function builder. It allows you to use a Logo-like syntax to create and draw lines in your Swift project.
let turtle = Turtle {
penDown()
loop(9) {
left(140)
forward(30)
left(-100)
forward(30)
}
penUp()
}
- FlooidLayout - Setup autolayout constraints in a declerative way
image.constraints { view in
view.centerXAnchor == container.centerXAnchor
view.topAnchor == container.topAnchor + 20
view.widthAnchor == container.widthAnchor -- 20
view.heightAnchor == view.widthAnchor * 0.6
}
icon.constraints { view in
view.centerAnchor == iconContainer.centerAnchor
view.sizeAnchor == CGSize(width: 20, height: 20)
}
- ...
- MenuBuilder - A convenient way to create menus.
let menu = NSMenu {
MenuItem("Click me")
.onSelect { print("clicked!") }
MenuItem("Item with a view")
.view {
MyMenuItemView() // any SwiftUI view
}
SeparatorItem()
MenuItem("About") {
// rendered as disabled items in a submenu
MenuItem("Version 1.2.3")
MenuItem("Copyright 2021")
}
MenuItem("Quit")
.shortcut("q")
.onSelect { NSApp.terminate(nil) }
}
// later, to replace the menu items with different/updated ones:
menu.replaceItems {
MenuItem("New Item").onSelect { print("Hello!") }
}
- ...
- Pappe - A Proof of concept embedded interpreted synchronous DSL for Swift.
let m = Module { name in
activity (name.Wait, [name.ticks]) { val in
exec { val.i = val.ticks as Int }
whileRepeat(val.i > 0) {
exec { val.i -= 1 }
await { true }
}
}
activity (name.Main, []) { val in
cobegin {
strong {
doRun(name.Wait, [10])
}
weak {
loop {
doRun(name.Wait, [2])
exec { print("on every third") }
await { true }
}
}
weak {
loop {
doRun(name.Wait, [1])
exec { print("on every second") }
await { true }
}
}
}
exec { print("done") }
}
}
- SyntaxBuilder - A toy Swift code generator based on SwiftSyntax
import SyntaxBuilder
struct UserSourceFile: SourceFile {
let idType: Type
@SyntaxListBuilder
var body: Body {
Import("Foundation")
Struct("User") {
Typealias("ID", of: idType)
Let("id", of: "ID")
.prependingComment("The user's ID.", .docLine)
Let("name", of: "String")
.prependingComment("The user's name.", .docLine)
Var("age", of: "Int")
.prependingComment("The user's age.", .docLine)
ForEach(0 ..< 3) { i in
Let("value\(i)", of: "String")
.prependingNewline()
}
}
.prependingComment("""
User is an user.
<https://github.com/akkyie/SyntaxBuilder/>
""", .docBlock)
}
}