awesome-result-builders
A list of cool DSLs made with Swift 5.4βs @resultBuilder
As of Swift 5.4,
functionBuilder
has been renamed toresultBuilder
Feel free to contribute if you make or find something awesome.
Contents
-
Projects
Guides
A list of helpful guides/tutorials on result 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
Data
- BitWiser - A simple library to help you in dealing with bytes, bits, nibbles and Data
Data {
[UInt8(0)]
UInt8(1)
Int8(2)
"\u{03}"
Int16(1284)
if dataClause {
CustomData()
}
}
Array<Byte> {
0b1010_1010
0b1100_1100
UInt8(32)
[0x05, 0x06]
Byte(0x01)
}
- BoolBuilder - Build complex Bool values in an easy to understasnd way while perserving short-circuit semantics and exception handling capabilities
let condition: Bool = all {
any {
conditionA
conditionB
.inverted
either {
conditionC
} or: {
conditionD
}
}
conditionE
}
Dependency Injection
- 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)
}
GraphQL
- 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
- 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)
- Mongrel - Build declarative HTML in Swift.
struct IndexPage: HTML {
var body: some HTMLConvertible {
Root(language: .en) {
Body {
Group {
Text("Welcome to Mongrel!")
.heading(.h1)
Text("A Swift and HTML hybrid supporting:")
List(.unordered) {
Text("CSS")
.paragraph()
Text("Javascript")
.paragraph()
}
.class("list")
}
}
.id("main-body")
}
}
}
- Swep - Writing type-safe HTML/CSS declaratively.
let titillimFont: StaticString = """
https://fonts.googleapis.com/css2?family=\
Titillium+Web:ital,wght@0,200;0,300;0,400;\
0,600;0,700;0,900;1,200;1,300;1,400;1,600;\
1,700&display=swap
"""
let page = document {
html {
head {
title("Hello, Swep!")
style {
`import`(titillimFont)
selector("*, *::before, *::after") {
margin(0)
padding(0)
}
selector("body") {
margin(0, .auto)
backgroundColor(.hex(0x111))
fontFamily("'Titillium Web', sans-serif")
}
}
}
body {
h1("π swift-web-page (swep)")
ul {
li("Write html documents along with css")
.fontWeight(.bolder)
li("Bring all swift-language features out of the box")
#if swift(>=5.1)
for version in 1...4 {
if version != 2 {
li("supporting swift v5.\(version)")
}
}
#endif
}
blockquote("Enjoy! βοΈπ")
}
}
}
- ...
Parsing
- HTMLParserBuilder - Build your HTML parser with declarative syntax and strongly-typed result.
struct Group {
let h1: String
let h2: String
}
let capture = HTML {
Capture("#group h1", transform: \.textContent)
Capture("#group h2", transform: \.textContent)
} transform: { (output: (String, String)) -> Group in
return Group(
h1: output.0,
h2: output.1
)
} // => HTML<Group>
- DeepCodable - Encode and decode deeply-nested data into flat Swift objects
struct SomeObject: DeepCodable {
static let codingTree = CodingTree {
Key("a", "b", "c") {
Key("d1", "e1", containing: \._e1)
Key("d2", "e2", "f2", containing: \._f2)
}
}
@Value var e1: String
@Value var f2: String
}
let json = """
{
"a": {
"b": {
"c": {
"d1": {
"e1": "Some value"
},
"d2": {
"e2": {
"f2": "Other value"
}
}
}
}
}
}
"""
let jsonData = json.data(using: .utf8)!
let object = try JSONDecoder().decode(SomeObject.self, from: jsonData)
print(object.e1) // "Some value"
print(object.f2) // "Other value"
- ...
Networking
- 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"
- ...
NSAttributedString
- 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)
}
- ...
REST
- 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 }
}
}
}
- ...
Server-Side
- 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()
- VaporDSL - Declarative, structured syntax for Vapor.
Group("api") {
// GET /api/
Route(use: index)
// GET /api/todos
Route("todos") { req in
return req.view.render("todos")
}
// POST /api/todos
Route("todos", on: .POST, use: todo)
}
- ...
SwiftUI
- 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.
Testing
- Rorschach - Write XCTest tests in BDD style π€·π»ββοΈ
expect {
Given("I have a universe without any stars") {
universe.numberOfStars = 0
}
When("I add a couple of stars") {
universe.numberOfStars = 23
}
Then("I can see the stars I have added β¨") {
XCTAssertEqual(universe.numberOfStars, 23)
}
}
- SwiftValidation β Declarative way to validate our object.
try validate(user) {
validate(\.id).isPositive()
validate(\.email) {
isNotEmpty()
isEmail()
}
}
UIKit
- 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)
}
- ...
AppKit
- 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!") }
}
- ...
Other
- 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)
}
}
- Narratore - A library to generate interactive stories and narrative games, that uses a DSL to write the story.
import Narratore
struct MyFirstScene: Scene {
typealias Game = MyGame
static let branches: [RawBranch<MyGame>] = [
Main.raw,
]
enum Main: Branch {
typealias Anchor = String
@BranchBuilder<Self>
static func getSteps(for _: MyFirstScene) -> [BranchStep<Self>] {
"Welcome"
"This is your new game, built with narratore".with(tags: [.init("Let's play some sound effect!")])
check {
if $0.world.isEnjoyable {
"Enjoy!"
}
}
"Now choose".with(anchor: "We could jump right here from anywhere")
choose { _ in
"Go to second scene, main path".onSelect {
"Let's go to the second scene!"
.with(id: "We can keep track of this message")
.then(.transitionTo(MySecondScene.init(magicNumber: 42)))
}
"Go to second scene, alternate path".onSelect {
"Going to the alternate path of the second scene"
.then(.transitionTo(MySecondScene.Other.self, scene: .init(magicNumber: 43)))
}
}
}
}
}