Project updates from Template #1

Merged
javier merged 123 commits from project/update-from-template into main 2026-09-04 13:40:36 +00:00
2 changed files with 30 additions and 4 deletions
Showing only changes of commit 88bcae9dc9 - Show all commits
@@ -1,21 +1,25 @@
/// A file extension used by an ``Asset``. /// A file extension used by an ``Asset``.
/// ///
/// Each case's raw value is the extension itself (e.g. `"css"`), which an asset appends to its file name when resolving paths. /// Each case's raw value is the extension itself (e.g. `"css"`), which an asset appends to its file name when resolving paths.
public enum AssetExtension: String, Sendable { public enum AssetExtension: String, CaseIterable, Sendable {
/// A Cascading Style Sheets file. /// A Cascading Style Sheets file.
case css case css
/// A Windows icon image.
case ico
/// A JPEG image.
case jpg
/// A JavaScript file. /// A JavaScript file.
case js case js
/// A Portable Network Graphics image. /// A Portable Network Graphics image.
case png case png
/// A Windows icon image.
case ico
/// A Scalable Vector Graphics image. /// A Scalable Vector Graphics image.
case svg case svg
/// A plain text file. /// A plain text file.
case txt case txt
/// A web application manifest file. /// A web application manifest file.
case webmanifest case webmanifest
/// A WebP image.
case webp
/// An Extensible Markup Language file. /// An Extensible Markup Language file.
case xml case xml
} }
@@ -30,12 +34,14 @@ public extension AssetExtension {
var contentType: String { var contentType: String {
switch self { switch self {
case .css: "text/css" case .css: "text/css"
case .ico: "image/vnd.microsoft.icon"
case .jpg: "image/jpeg"
case .js: "text/javascript" case .js: "text/javascript"
case .png: "image/png" case .png: "image/png"
case .ico: "image/vnd.microsoft.icon"
case .svg: "image/svg+xml" case .svg: "image/svg+xml"
case .txt: "text/plain" case .txt: "text/plain"
case .webmanifest: "application/manifest+json" case .webmanifest: "application/manifest+json"
case .webp: "image/webp"
case .xml: "application/xml" case .xml: "application/xml"
} }
} }
@@ -45,6 +51,9 @@ public extension AssetExtension {
switch self { switch self {
case .css: "css" case .css: "css"
case .js: "js" case .js: "js"
case .jpg,
.mp4,
.webp: "media"
default: nil default: nil
} }
} }
@@ -32,6 +32,17 @@ struct AssetExtensionTests {
#expect(fileExtension.folder == folder) #expect(fileExtension.folder == folder)
} }
// MARK: CaseIterable tests
@Test
func `covers every case in the parameterised tests`() {
// `zip` stops at the shorter sequence, so a case missing from the arrays below is silently untested rather
// than failing this is what catches that.
#expect(Self.extensions == AssetExtension.allCases)
#expect(Self.contentTypes.count == AssetExtension.allCases.count)
#expect(Self.folders.count == AssetExtension.allCases.count)
}
} }
// MARK: - Helpers // MARK: - Helpers
@@ -44,6 +55,8 @@ private extension AssetExtensionTests {
.css, .css,
.js, .js,
.png, .png,
.jpg,
.webp,
.ico, .ico,
.svg, .svg,
.txt, .txt,
@@ -54,6 +67,8 @@ private extension AssetExtensionTests {
"text/css", "text/css",
"text/javascript", "text/javascript",
"image/png", "image/png",
"image/jpeg",
"image/webp",
"image/vnd.microsoft.icon", "image/vnd.microsoft.icon",
"image/svg+xml", "image/svg+xml",
"text/plain", "text/plain",
@@ -64,6 +79,8 @@ private extension AssetExtensionTests {
"css", "css",
"js", "js",
nil, nil,
"media",
"media",
nil, nil,
nil, nil,
nil, nil,