Created
November 29, 2021 03:27
-
-
Save auramagi/a40833494b626c3166ede63ffc39cbf3 to your computer and use it in GitHub Desktop.
Parse Swift type into a tree where the child nodes are the generic types. Useful for making trees from SwiftUI View types.
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
import Foundation | |
final class BracketScanner { | |
let text: String | |
init(text: String) { | |
self.text = text.trimmingCharacters(in: CharacterSet(charactersIn: "()")) | |
} | |
lazy var scanner: Scanner = { | |
let scanner = Scanner(string: text) | |
scanner.charactersToBeSkipped = nil | |
return scanner | |
}() | |
func parse() -> (String, [String]) { | |
let result = (parseId(), parseTypes()) | |
return result | |
} | |
private func parseId() -> String { | |
scanner.scanUpToString("<") ?? "" | |
} | |
private func parseTypes() -> [String] { | |
_ = scanner.scanCharacters(from: CharacterSet(charactersIn: "<")) | |
var result: [String] = [] | |
var pending = "" | |
var nest = 0 | |
let controlSet = CharacterSet(charactersIn: "<,>") | |
while !scanner.isAtEnd { | |
let chunk = scanner.scanUpToCharacters(from: controlSet) ?? "" | |
pending += chunk | |
guard let control = scanner.scanCharacter() else { | |
result.append(pending) | |
break | |
} | |
switch control { | |
case "<": | |
nest += 1 | |
pending.append(control) | |
case ",": | |
if nest == 0 { | |
result.append(pending) | |
pending = "" | |
} else { | |
pending.append(control) | |
} | |
case ">": | |
if nest == 0 { | |
result.append(pending) | |
pending = "" | |
} else { | |
pending.append(control) | |
nest -= 1 | |
} | |
default: break | |
} | |
} | |
return result | |
} | |
} |
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
import Foundation | |
struct Tree<A> { | |
var value: A | |
var children: [Tree<A>] = [] | |
} | |
extension Mirror { | |
func makeTree() -> Tree<String> { | |
let typeString = String(describing: subjectType) | |
return typeString.makeTypeTree() | |
} | |
} | |
extension String { | |
func makeTypeTree() -> Tree<String> { | |
let (id, typeChildren) = BracketScanner(text: self).parse() | |
return .init( | |
value: id, | |
children: typeChildren.map { $0.makeTypeTree() } | |
) | |
} | |
} | |
extension View { | |
var typeTree: Tree<String> { | |
Mirror(reflecting: self).makeTree() | |
} | |
} |
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
import SwiftUI | |
let tree = Text("Hello World") | |
.padding() | |
.background(Color.red) | |
.typeTree | |
dump(tree) | |
/* | |
▿ Trees.Tree<Swift.String> | |
- value: "ModifiedContent" | |
▿ children: 2 elements | |
▿ Trees.Tree<Swift.String> | |
- value: "ModifiedContent" | |
▿ children: 2 elements | |
▿ Trees.Tree<Swift.String> | |
- value: "Text" | |
- children: 0 elements | |
▿ Trees.Tree<Swift.String> | |
- value: " _PaddingLayout" | |
- children: 0 elements | |
▿ Trees.Tree<Swift.String> | |
- value: " _BackgroundModifier" | |
▿ children: 1 element | |
▿ Trees.Tree<Swift.String> | |
- value: "Color" | |
- children: 0 elements | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment