diff --git a/Sources/DocCMiddleware/Public/Middlewares/DocCMiddleware.swift b/Sources/DocCMiddleware/Public/Middlewares/DocCMiddleware.swift index c9f804e..2f33c20 100644 --- a/Sources/DocCMiddleware/Public/Middlewares/DocCMiddleware.swift +++ b/Sources/DocCMiddleware/Public/Middlewares/DocCMiddleware.swift @@ -20,6 +20,28 @@ import struct Hummingbird.Response import struct Logging.Logger /// A middleware that proxies requests to `DocC` documentation containers within a hosting app. +/// +/// This middleware routes the contents of a `DocC` documentation container, defined by its resource URI paths, following these rules: +/// +/// 1. *Redirects the URI path `/` to the path `//`*; +/// 2. *Redirects the URI path `//` to the path `//documentation`* +/// 3. *Redirects the URI path `//documentation` to the path `//documentation/`* +/// 4. *Redirects the URI path `//tutorials` to the path `//tutorials/`* +/// 5. *Redirects the URI path `//documentation/` to the resource on `/.doccarchive/documentation//index.html`* +/// 6. *Redirects the URI path `//tutorials/` to the resource on `/.doccarchive/tutorials//index.html`* +/// 7. *Redirects the URI path `//data/documentation.json` to the resource on `/.doccarchive/data/documentation/.json`* +/// 8. *Redirects the URI path `//favicon.ico` to the resource on `/.doccarchive/favicon.ico`* +/// 9. *Redirects the URI path `//favicon.svg` to the resource on `/.doccarchive/favicon.svg`* +/// 10. *Redirects the URI path `//theme-settings.json` to the resource on `/.doccarchive/theme-settings.json`* +/// 11. *Redirects the URI path `//css/` to the resource on `/.doccarchive/css/`* +/// 12. *Redirects the URI path `//data/` to the resource on `/.doccarchive/data/`* +/// 13. *Redirects the URI path `//downloads/` to the resource on `/.doccarchive/downloads/`* +/// 14. *Redirects the URI path `//images/` to the resource on `/.doccarchive/images/`* +/// 15. *Redirects the URI path `//img/` to the resource on `/.doccarchive/img/`* +/// 16. *Redirects the URI path `//index/` to the resource on `/.doccarchive/index/`* +/// 17. *Redirects the URI path `//js/` to the resource on `/.doccarchive/js/`* +/// 18. *Redirects the URI path `//videos/` to the resource on `/.doccarchive/videos/`* +/// public struct DocCMiddleware { // MARK: Properties @@ -102,52 +124,63 @@ extension DocCMiddleware: RouterMiddleware { // MARK: Functions public func handle( - _ input: Input, + _ request: Input, context: any Context, next: (Input, any Context) async throws -> Output ) async throws -> Output { guard - let uriPath = checkURI(input.uri), + let uriPath = checkURI(request.uri), let uriData = prepareURIPath(uriPath) else { - return try await next(input, context) + return try await next(request, context) } - if uriData.resourcePath == .Path.forwardSlash { - // rule #1: Redirects URI root to `/`. - // rule #2: Redirects URI resources with `/` to `/documentation`. + let rootPaths: [String] = [ + String(format: .Format.Path.root, uriData.archiveName), + String(format: .Format.Path.folder, uriData.archiveName) + ] + + if rootPaths.contains(uriData.resourcePath) { return redirectURI( uriPath.hasSuffix(.Path.forwardSlash) + // Rule #2: Redirects the URI path // to the path //documentation ? String(format: .Format.Path.documentation, uriPath) - : String(format: .Format.Path.forwardSlash, uriPath), - with: (input, context) + // Rule #1: Redirects the URI path / to the path // + : String(format: .Format.Path.forwardSlash, uriPath), + with: (request, context) ) } - + for assetFile in AssetFile.allCases { if uriData.resourcePath.contains(assetFile.path) { return try await serveURI( assetFile == .documentation - // Rule #6: Redirects URI resources with `/data/documentation.json` to the file in the `data/documentation/` - // folder that has the name of the module and ends with the `.json` extension in the *DocC* archive container. - ? String(format: .Format.Path.documentationJSON, uriData.archiveName) - // Rule #7: Redirect URI resources for static files (`favicon.ico`, `favicon.svg`, and `theme-settings.json`) - // to their respective files in the *DocC* archive container. + // Rule #7: Redirects the URI path //data/documentation.json to the resource on /.doccarchive/data/documentation/.json + ? String(format: .Format.Path.documentationJSON, uriData.archiveReference) + // Rule #8: Redirects the URI path `//favicon.ico` to the resource on `/.doccarchive/favicon.ico` + // Rule #9: Redirects the URI path `//favicon.svg` to the resource on `/.doccarchive/favicon.svg` + // Rule #10: Redirects the URI path `//theme-settings.json` to the resource on `/.doccarchive/theme-settings.json` : uriData.resourcePath, at: uriData.archivePath, - with: (input, context) + with: (request, context) ) } } for assetFolder in AssetFolder.allCases { if uriData.resourcePath.contains(assetFolder.path) { - // Rule #8: Redirect URI resources for asset files (`/css/`, `/data/`, `/downloads/`, `/images/`, `/img/`, - // `/index/`, `/js/`, or `/videos/`) to their respective files in the *DocC* archive container. + // Rule #11: Redirects the URI path `//css/` to the resource on `/.doccarchive/css/` + // Rule #12: Redirects the URI path `//data/` to the resource on `/.doccarchive/data/` + // Rule #13: Redirects the URI path `//downloads/` to the resource on `/.doccarchive/downloads/` + // Rule #14: Redirects the URI path `//images/` to the resource on `/.doccarchive/images/` + // Rule #15: Redirects the URI path `//img/` to the resource on `/.doccarchive/img/` + // Rule #16: Redirects the URI path `//index/` to the resource on `/.doccarchive/index/` + // Rule #17: Redirects the URI path `//js/` to the resource on `/.doccarchive/js/` + // Rule #18: Redirects the URI path `//videos/` to the resource on `/.doccarchive/videos/` return try await serveURI( uriData.resourcePath, at: uriData.archivePath, - with: (input, context) + with: (request, context) ) } } @@ -155,24 +188,25 @@ extension DocCMiddleware: RouterMiddleware { for documentationFolder in DocumentationFolder.allCases { if uriData.resourcePath.contains(documentationFolder.path) { if uriData.resourcePath.hasSuffix(.Path.forwardSlash) { - // Rule #5: Redirect URI resources for `/documentation/` and `/tutorials/` folders to their respective `index.html` file. + // Rule #5: Redirects the URI path //documentation/ to the resource on /.doccarchive/documentation//index.html + // Rule #6: Redirects the URI path //tutorials/ to the resource on /.doccarchive/tutorials//index.html return try await serveURI( - String(format: .Format.Path.index, documentationFolder.path, uriData.archiveName), + String(format: .Format.Path.index, documentationFolder.path, uriData.archiveReference), at: uriData.archivePath, - with: (input, context) + with: (request, context) ) } else { - // rule #3: Redirects URI resources with `/documentation` to `/documentation/`. - // rule #4: Redirects URI resources with `/tutorials` to `/tutorials/`. + // Rule #3: Redirects the URI path //documentation to the path //documentation/ + // Rule #4: Redirects the URI path //tutorials to the path //tutorials/ return redirectURI( String(format: .Format.Path.forwardSlash, uriPath), - with: (input, context) + with: (request, context) ) } } } - return try await next(input, context) + return try await next(request, context) } }