Skip to content

Commit b36a4e9

Browse files
committed
feat: Clean up Item dates
Closes #22 BREAKING CHANGE: Item.published has been renamed to Item.date.
1 parent c763b47 commit b36a4e9

File tree

5 files changed

+38
-25
lines changed

5 files changed

+38
-25
lines changed

Sources/Saga/Item.swift

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,24 @@ public struct EmptyMetadata: Metadata {
1010

1111
/// A type-erased version of ``Item``.
1212
public protocol AnyItem: AnyObject {
13+
var absoluteSource: Path { get }
1314
var relativeSource: Path { get }
1415
var filenameWithoutExtension: String { get }
1516
var relativeDestination: Path { get set }
1617
var title: String { get set }
17-
var rawContent: String { get set }
1818
var body: String { get set }
19-
var published: Date { get set }
20-
var created: Date { get set }
21-
var lastModified: Date { get set }
19+
var date: Date { get set }
20+
var lastModified: Date { get }
2221
var url: String { get }
2322
}
2423

2524
/// A model reprenting an item.
2625
///
2726
/// An item can be any text file (like a Markdown or RestructedText file). ``Reader``s will turn the file into an ``Item``, and ``Writer``s will turn the ``Item`` into a `String` (for example HTML or RSS) to be written to disk.
2827
public class Item<M: Metadata>: AnyItem {
28+
/// The absolute path of the file
29+
public let absoluteSource: Path
30+
2931
/// The path of the file, relative to the site's `input`.
3032
public let relativeSource: Path
3133

@@ -35,32 +37,27 @@ public class Item<M: Metadata>: AnyItem {
3537
/// The title of the item.
3638
public var title: String
3739

38-
/// The raw contents of the file, not parsed in any way.
39-
public var rawContent: String
40-
4140
/// The body of the file, without the metadata header, and without the first title.
4241
public var body: String
4342

44-
/// The published date of the item.
45-
public var published: Date
46-
47-
/// The creation date of the item.
48-
public var created: Date
43+
/// The date of the item, defaults to the creation date.
44+
/// Pleaae note that the creation date value can be inconsistent when cloning or pulling from git, see https://github.com/loopwerk/Saga/issues/21.
45+
public var date: Date
4946

5047
/// The last modified date of the item.
51-
public var lastModified: Date
48+
/// Pleaae note that this value can be inconsistent when cloning or pulling from git, see https://github.com/loopwerk/Saga/issues/21.
49+
public let lastModified: Date
5250

5351
/// The parsed metadata. ``Metadata`` can be any `Codable` object.
5452
public var metadata: M
5553

56-
public init(relativeSource: Path, relativeDestination: Path, title: String, rawContent: String, body: String, published: Date, created: Date, lastModified: Date, metadata: M) {
54+
public init(absoluteSource: Path, relativeSource: Path, relativeDestination: Path, title: String, body: String, date: Date, lastModified: Date, metadata: M) {
55+
self.absoluteSource = absoluteSource
5756
self.relativeSource = relativeSource
5857
self.relativeDestination = relativeDestination
5958
self.title = title
60-
self.rawContent = rawContent
6159
self.body = body
62-
self.published = published
63-
self.created = created
60+
self.date = date
6461
self.lastModified = lastModified
6562
self.metadata = metadata
6663
}

Sources/Saga/ProcessingStep.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,30 @@ internal class AnyProcessStep {
4444
unhandledFileContainer.handled = true
4545

4646
do {
47-
// Turn the file into an Item
48-
let item = try await reader.convert(unhandledFileContainer.path, unhandledFileContainer.relativePath, unhandledFileContainer.relativePath.makeOutputPath(itemWriteMode: itemWriteMode))
47+
// Use the Reader to convert the contents of the file to HTML
48+
let partialItem = try await reader.convert(unhandledFileContainer.path)
49+
50+
// Then we try to decode the frontmatter (which is just a [String: String] dict) to proper metadata
51+
let decoder = makeMetadataDecoder(for: partialItem.frontmatter ?? [:])
52+
let date = try resolveDate(from: decoder)
53+
let metadata = try M(from: decoder)
54+
55+
// Create the Item instance
56+
let item = Item(
57+
absoluteSource: unhandledFileContainer.path,
58+
relativeSource: unhandledFileContainer.relativePath,
59+
relativeDestination: unhandledFileContainer.relativePath.makeOutputPath(itemWriteMode: itemWriteMode),
60+
title: partialItem.title ?? "",
61+
body: partialItem.body,
62+
date: date ?? unhandledFileContainer.path.creationDate ?? Date(),
63+
lastModified: unhandledFileContainer.path.modificationDate ?? Date(),
64+
metadata: metadata)
4965

5066
// Process the Item if there's an itemProcessor
5167
if let itemProcessor = step.itemProcessor {
5268
await itemProcessor(item)
5369
}
54-
70+
5571
// Store the generated Item if it passes the filter
5672
if step.filter(item) {
5773
unhandledFileContainer.item = item
@@ -67,13 +83,13 @@ internal class AnyProcessStep {
6783
}
6884
}
6985

70-
step.items = items.sorted(by: { left, right in left.published > right.published })
86+
step.items = items.sorted(by: { left, right in left.date > right.date })
7187
}
7288

7389
runWriters = {
7490
let allItems = fileStorage
7591
.compactMap(\.item)
76-
.sorted(by: { left, right in left.published > right.published })
92+
.sorted(by: { left, right in left.date > right.date })
7793

7894
for writer in step.writers {
7995
try writer.run(step.items, allItems, fileStorage, outputPath, step.folder ?? "", fileIO)

Sources/Saga/Reader.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public struct Reader<M: Metadata> {
4242
/// Which file extensions can be handled by this reader? For example `md` or `rst`.
4343
var supportedExtensions: [String]
4444

45-
public typealias Converter = (_ absoluteSource: Path, _ relativeSource: Path, _ relativeDestination: Path) async throws -> Item<M>
45+
public typealias Converter = (_ absoluteSource: Path) async throws -> (title: String?, body: String, frontmatter: [String:String]?)
4646

4747
/// The function that will do the actual work of reading and converting a file path into an ``Item``.
4848
var convert: Converter

Sources/Saga/Writer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public extension Writer {
6969
var itemsPerYear = [Int: [Item<M>]]()
7070

7171
for item in items {
72-
let year = item.published.year
72+
let year = item.date.year
7373
if var itemsArray = itemsPerYear[year] {
7474
itemsArray.append(item)
7575
itemsPerYear[year] = itemsArray

Sources/Saga/utils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public func publicationDateInFilename<M>(item: Item<M>) async {
3636
}
3737

3838
// Set the date
39-
item.published = date
39+
item.date = date
4040

4141
// And remove the first 11 characters from the filename
4242
let first11 = String(item.relativeSource.lastComponentWithoutExtension.prefix(11))

0 commit comments

Comments
 (0)