Skip to content

Instantly share code, notes, and snippets.

@jaredsinclair
Created April 8, 2019 01:02
Show Gist options
  • Save jaredsinclair/7ea54d4e3e75e6394f72a53b5ed548df to your computer and use it in GitHub Desktop.
Save jaredsinclair/7ea54d4e3e75e6394f72a53b5ed548df to your computer and use it in GitHub Desktop.

Revisions

  1. jaredsinclair created this gist Apr 8, 2019.
    110 changes: 110 additions & 0 deletions Importer.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,110 @@
    import Foundation

    /*

    Alls you gotta do is (in Main.swift):

    1. Initialize an Importer with the file URL to the JSON file (origin) and a URL to the directory that will contain all the Jekyll-formatted posts (destination).
    2. Call the `run()` method on the Importer.

    */

    struct Post: Codable {
    static let filenameFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "YYYY-MM-dd"
    return formatter
    }()

    static let frontmatterFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
    return formatter
    }()

    static let disallowedCharacters = NSCharacterSet
    .alphanumerics
    .union(CharacterSet(charactersIn: "-"))
    .inverted

    let title: String
    let url: String
    let content: String
    let published: Date

    var fileName: String {
    let date = Post.filenameFormatter.string(from: published)
    let slug = title
    .lowercased()
    .replacingOccurrences(of: " ", with: "-")
    .components(separatedBy: Post.disallowedCharacters)
    .joined(separator: "")
    .prefix(32)
    .trimmingCharacters(in: CharacterSet(charactersIn: "-"))
    return "\(date)-\(slug).html"
    }

    var fileContent: String {
    let dateStamp = Post.frontmatterFormatter.string(from: published)
    return """
    ---
    layout: post
    title: "\(title)"
    date: \(dateStamp)
    categories:
    navtab: blog
    ---
    \(content)
    """
    }
    }

    public final class Importer {

    let origin: URL
    let destination: URL
    let formatter: ISO8601DateFormatter

    public init(origin: URL, destination: URL) {
    print("Will read data from \(origin)")
    self.origin = origin
    self.destination = destination
    self.formatter = ISO8601DateFormatter()
    // init satisfied
    formatter.formatOptions = formatter.formatOptions.union(.withFractionalSeconds)
    }

    public func run() throws {
    let data = try Data(contentsOf: origin)
    try decode(data)
    }

    private func decode(_ data: Data) throws {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .custom(formatter.parseDate)
    let posts = try decoder.decode([Post].self, from: data)
    posts.forEach { post in
    let fileUrl = destination.appendingPathComponent(post.fileName, isDirectory: false)
    let fileContent = post.fileContent.data(using: .utf8)!
    try! fileContent.write(to: fileUrl, options: .atomicWrite)
    }
    }

    }

    extension ISO8601DateFormatter {

    enum DateError: Error {
    case invalidDateFormat
    }

    func parseDate(using decoder: Decoder) throws -> Date {
    let string = try decoder.singleValueContainer().decode(String.self)
    guard let date = date(from: string) else {
    throw DateError.invalidDateFormat
    }
    return date
    }

    }