Skip to content

Instantly share code, notes, and snippets.

@chriseidhof
Created June 29, 2021 09:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chriseidhof/8a4b917ac1f7db992c4472a04362e950 to your computer and use it in GitHub Desktop.
Save chriseidhof/8a4b917ac1f7db992c4472a04362e950 to your computer and use it in GitHub Desktop.
Toml To Yaml
import TOMLDeserializer
import Foundation
import Yams
let postsDir = URL(fileURLWithPath: "/Users/chris/objc.io/chriseidhofnl/site/posts")
let fm = FileManager.default
let contents = try fm.contentsOfDirectory(atPath: postsDir.path)
for file in contents {
if file.hasPrefix(".") { continue }
let path = postsDir.appendingPathComponent(file)
let contents = try! String(contentsOf: path)
let (toml, body) = try contents.parseMarkdownWithFrontMatter()
guard let t = toml else { continue }
let parsed = try TOMLDeserializer.tomlTable(with: t)
let dumped = try Yams.dump(object: parsed)
let result = "---\n\(dumped)---\(body)"
try result.write(to: path, atomically: true, encoding: .utf8)
}
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "TomlToYaml",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.executable(
name: "TomlToYaml",
targets: ["TomlToYaml"]),
],
dependencies: [
.package(url: "https://github.com/dduan/TOMLDeserializer", from: "0.2.5"),
.package(url: "https://github.com/jpsim/Yams", from: "2.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "TomlToYaml",
dependencies: ["TOMLDeserializer", "Yams"]),
.testTarget(
name: "TomlToYamlTests",
dependencies: ["TomlToYaml"]),
]
)
//
// File.swift
//
//
// Created by Chris Eidhof on 11.04.20.
//
import Foundation
extension Character {
public var isDecimalDigit: Bool {
return self.isHexDigit && self.hexDigitValue! < 10 // todo?
}
public var isIdentifier: Bool {
return isLetter || isNumber || self == "_" || self == "-"
}
public var isIdentifierStart: Bool {
return isLetter || isNumber || self == "_"
}
}
extension Substring {
@discardableResult mutating public func remove(prefix: String) -> Bool {
guard hasPrefix(prefix) else { return false }
removeFirst(prefix.count)
return true
}
@discardableResult
mutating public func remove(while cond: (Element) -> Bool) -> Self? {
guard let end = firstIndex(where: { !cond($0) }) else {
let remainder = self
self.removeAll()
return remainder
}
let result = self[..<end]
self = self[end..<endIndex]
return result
}
@discardableResult
mutating public func removeLine() -> Self? {
guard let newLine = firstIndex(where: { $0.isNewline }) else {
let result = self
self.removeAll()
return result
}
let end = self.index(after: newLine)
let result = self[..<end]
self = self[end..<endIndex]
return result
}
mutating public func skipWS() {
remove(while: { $0.isWhitespace })
}
mutating public func skipWSWithoutNewlines() {
remove(while: { $0.isWhitespace && !$0.isNewline })
}
}
//
// File.swift
//
//
// Created by Chris Eidhof on 01.06.21.
//
import Foundation
extension String {
// Parses a yaml front matter delimeted by ---
public func parseMarkdownWithFrontMatter() throws -> (toml: String?, markdown: String) {
var remainder = self[...]
remainder.remove(while: { $0.isWhitespace })
if remainder.remove(prefix: "+++") {
let start = remainder.startIndex
var end = remainder.startIndex
while !remainder.isEmpty, !remainder.remove(prefix: "+++") {
remainder.removeLine()
end = remainder.startIndex
}
let yaml = String(self[start..<end])
return (toml: yaml, markdown: String(remainder))
}
return (toml: nil, markdown: self)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment