Skip to content

Commit

Permalink
Rework themes, contents, and types (#25)
Browse files Browse the repository at this point in the history
- Rework entire configuration loader logic
- Add new transformers configuration section
- Better log for theme urls

## Breaking changes

- path: `src/content` folder is now `contents` by default
- path: `src/types` are moved under the themes, e.g.
`theme/default/types`
- path: `theme_overrides` is now `theme/overrides`
  • Loading branch information
tib authored Oct 11, 2024
1 parent 2e4d2d5 commit 4f2adde
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 231 deletions.
11 changes: 9 additions & 2 deletions Sources/ToucanSDK/Extensions/Dictionary+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,15 @@ extension Dictionary where Key == String, Value == Any {
///
/// - Parameter keyPath: The key path string, where keys are separated by dots.
/// - Returns: The string at the specified key path
func string(_ keyPath: String) -> String? {
value(keyPath, as: String.self)
func string(
_ keyPath: String,
allowingEmptyValue: Bool = false
) -> String? {
let result = value(keyPath, as: String.self)
if allowingEmptyValue {
return result
}
return result.emptyToNil
}

/// Retrieves the integer associated with the given key path.
Expand Down
4 changes: 1 addition & 3 deletions Sources/ToucanSDK/Mustache/MustacheToHTMLRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,8 @@ public struct MustacheToHTMLRenderer {
self.library = MustacheLibrary(templates: templates)
self.ids = Array(templates.keys)

logger.trace("Templates url: `\(templatesUrl.absoluteString)`")
logger.trace("Template overrides url: `\(overridesUrl.absoluteString)`")
logger.trace(
"Available templates: \(ids.map { "`\($0)`" }.joined(separator: ", "))"
"Available templates: \(ids.sorted().map { "`\($0)`" }.joined(separator: ", "))"
)
}

Expand Down
285 changes: 276 additions & 9 deletions Sources/ToucanSDK/Source/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,49 @@
struct Config {

struct Location {

enum Keys {
static let folder = "folder"
}

let folder: String

init(folder: String) {
self.folder = folder
}

init?(_ dict: [String: Any]) {
guard let folder = dict.string(Keys.folder) else {
return nil
}
self.folder = folder
}
}

// MARK: -

struct Site {

enum Keys {
static let baseUrl = "baseUrl"
static let title = "title"
static let description = "description"
static let language = "language"
static let dateFormat = "dateFormat"
static let noindex = "noindex"
static let hreflang = "hreflang"

static let allKeys: [String] = [
Keys.baseUrl,
Keys.title,
Keys.description,
Keys.language,
Keys.dateFormat,
Keys.noindex,
Keys.hreflang,
]
}

struct Hreflang: Codable {
let lang: String
let url: String
Expand All @@ -22,32 +60,261 @@ struct Config {
let title: String
let description: String
let language: String?
let dateFormat: String?
let noindex: Bool?
let hreflang: [Hreflang]?
let dateFormat: String
let noindex: Bool
let hreflang: [Hreflang]
let userDefined: [String: Any]

init(
baseUrl: String,
title: String,
description: String,
language: String?,
dateFormat: String,
noindex: Bool,
hreflang: [Hreflang],
userDefined: [String: Any]
) {
self.baseUrl = baseUrl
self.title = title
self.description = description
self.language = language
self.dateFormat = dateFormat
self.noindex = noindex
self.hreflang = hreflang
self.userDefined = userDefined
}

init(_ dict: [String: Any]) {
self.baseUrl =
dict.string(Keys.baseUrl)
?? Config.defaults.site.baseUrl

self.title =
dict.string(Keys.title)
?? Config.defaults.site.title

self.description =
dict.string(Keys.description)
?? Config.defaults.site.description

self.language = dict.string(Keys.language)

self.dateFormat =
dict.string(Keys.dateFormat)
?? Config.defaults.site.dateFormat

self.noindex =
dict.bool(Keys.noindex)
?? Config.defaults.site.noindex

self.hreflang = dict.array(Keys.hreflang, as: Hreflang.self)
self.userDefined = dict.filter { !Keys.allKeys.contains($0.key) }
}
}

// MARK: -

struct Themes {

enum Keys {
static let use = "use"
static let assets = "assets"
static let templates = "templates"
static let types = "types"
static let overrides = "overrides"
}

let use: String
let folder: String
let templates: Location
let assets: Location
let templates: Location
let types: Location
let overrides: Location

init(
use: String,
folder: String,
assets: Config.Location,
templates: Config.Location,
types: Config.Location,
overrides: Config.Location
) {
self.use = use
self.folder = folder
self.assets = assets
self.templates = templates
self.types = types
self.overrides = overrides
}

init(_ dict: [String: Any]) {
self.use =
dict.string(Keys.use)
?? Config.defaults.themes.use

self.folder =
dict.string(Location.Keys.folder)
?? Config.defaults.themes.folder

let assets = dict.dict(Keys.assets)
self.assets =
Location(assets)
?? Config.defaults.themes.assets

let templates = dict.dict(Keys.templates)
self.templates =
Location(templates)
?? Config.defaults.themes.templates

let overrides = dict.dict(Keys.overrides)
self.overrides =
Location(overrides)
?? Config.defaults.themes.overrides

let types = dict.dict(Keys.types)
self.types =
Location(types)
?? Config.defaults.themes.types
}
}

struct Content {
// MARK: -

struct Contents {

enum Keys {
static let dateFormat = "dateFormat"
static let assets = "assets"
}

let folder: String
let dateFormat: String
let assets: Location

init(
folder: String,
dateFormat: String,
assets: Config.Location
) {
self.folder = folder
self.dateFormat = dateFormat
self.assets = assets
}

init(_ dict: [String: Any]) {
self.folder =
dict.string(Location.Keys.folder)
?? Config.defaults.contents.folder

self.dateFormat =
dict.string(Keys.dateFormat)
?? Config.defaults.contents.dateFormat

let assets = dict.dict(Keys.assets)
self.assets =
Location(assets)
?? Config.defaults.themes.assets
}
}

struct Types {
// MARK: -

struct Transformers {

enum Keys {
static let pipelines = "pipelines"
}

struct Pipeline {
let types: [String]
let run: [String]
let render: Bool
}

let folder: String
let pipelines: [Pipeline]

init(
folder: String,
pipelines: [Pipeline]
) {
self.folder = folder
self.pipelines = pipelines
}

init(_ dict: [String: Any]) {
self.folder =
dict.string(Location.Keys.folder)
?? Config.defaults.transformers.folder

self.pipelines = dict.array(Keys.pipelines, as: Pipeline.self)
}
}

var site: Site
// MARK: -

enum Keys {
static let site = "site"
static let themes = "themes"
static let contents = "contents"
static let transformers = "transformers"
}

let site: Site
let themes: Themes
let types: Types
let content: Content
let contents: Contents
let transformers: Transformers

init(
site: Site,
themes: Themes,
contents: Contents,
transformers: Transformers
) {
self.site = site
self.themes = themes
self.contents = contents
self.transformers = transformers
}

init(_ dict: [String: Any]) {
self.site = .init(dict.dict(Keys.site))
self.themes = .init(dict.dict(Keys.themes))
self.contents = .init(dict.dict(Keys.contents))
self.transformers = .init(dict.dict(Keys.transformers))
}
}

extension Config {

static let `defaults` = Config(
site: .init(
baseUrl: "http://localhost:3000/",
title: "",
description: "",
language: nil,
dateFormat: "MMMM dd, yyyy",
noindex: false,
hreflang: [],
userDefined: [:]
),
themes: .init(
use: "default",
folder: "themes",
assets: .init(folder: "assets"),
templates: .init(folder: "templates"),
types: .init(folder: "types"),
overrides: .init(folder: "overrides")
),
contents: .init(
folder: "contents",
dateFormat: "yyyy-MM-dd HH:mm:ss",
assets: .init(folder: "assets")
),
transformers: .init(
folder: "transformers",
pipelines: []
)
)
}
Loading

0 comments on commit 4f2adde

Please sign in to comment.