Repository: apple/swift-docc (swift)

Issue:
[SR-15576] [Swift-DocC] Transform-for-static-hosting does not DocC's experimental custom header/footer feature

   |                  |                 |
   |------------------|-----------------|
   |Previous ID       | SR-15576      |
   |Radar             | rdar://problem/86298113         |
   |Original Reporter | @ethan-kusters      |
   |Type              | Bug    |

   <details>
  <summary>Additional Detail from JIRA</summary>

   |                  |                 |
   |------------------|-----------------|
   |Votes             | 0         |
   |Component/s       | Swift-DocC    |
   |Labels            | Bug        |
   |Assignee          | None      |
   |Priority          | Medium      |

   

   md5: c735028a1eb87105ac679771fac32b43

  </details>




**cloned to**:  
* [SR-15750](https://bugs.swift.org/browse/SR-15750) [Swift-DocC] `docc archive transform-for-static-hosting` should add support for experimental custom header/footer feature  

**relates to**:  
* [SR-15750](https://bugs.swift.org/browse/SR-15750) [Swift-DocC] `docc archive transform-for-static-hosting` should add support for experimental custom header/footer feature  


**Issue Description:**


Currently the \`transform-for-static-hosting\` action does not respect the experimental header/footer that can be provided in a DocC Catalog.

 

Since \`transform-for-static-hosting\` is still experimental, this lack of support did not block landing the initial implementation but it should be fixed for user's who want to host their docs in a static environment and take advantage of the experimental custom header/footer support.

 

The basics of what are needed to add support can be found here: [ethan-kusters@119770f](https://github.com/ethan-kusters/swift-docc/commit/119770f1651f591ade2f1bb66401b2039c90e670).

Pull request:
This copies custom headers and footers into all the index.html files when using --transform-for-static-hosting and
--experimental-enable-custom-templates.

Adds a test for this as well.

Bug/issue #, if applicable: #196 

## Summary

This fixes an issue where `index.html` files in the static output didn't have custom headers and footers (aside from the root `index.html`).

Per Ethan's advice in the originating issue, I moved `outputConsumer.consume(assetsInBundle: bundle)` further up the file to where some other pregeneration work seemed to be happening.

## Dependencies

None.

## Testing

You can either observe the output of the`testConvertWithCustomTemplatesForStaticHosting` test or run: `swift run docc convert --transform-for-static-hosting --experimental-enable-custom-templates SomeDoccBundle.docc` on a DocC bundle that has multiple pages of docs and a custom `header.html` file.

Steps:
1. Run the command above.
2. Verify that each page under /documentation has a custom header.

## Checklist

Make sure you check off the following items. If they cannot be completed, provide a reason.

- [x] Added tests
- [x] Ran the `./bin/test` script and it succeeded
- [x] Updated documentation if necessary (not really necessary here)

Patch:
diff --git a/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift b/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift
index 9fabe59a48..8256d0ae32 100644
--- a/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift
+++ b/Sources/SwiftDocC/Infrastructure/DocumentationConverter.swift
@@ -246,6 +246,9 @@ public struct DocumentationConverter: DocumentationConverterProtocol {
         let renderContext = RenderContext(documentationContext: context, bundle: bundle)
         
         try outputConsumer.consume(renderReferenceStore: renderContext.store)
+
+        // Copy images, sample files, and other static assets.
+        try outputConsumer.consume(assetsInBundle: bundle)
         
         let converter = DocumentationContextConverter(
             bundle: bundle,
@@ -328,13 +331,6 @@ public struct DocumentationConverter: DocumentationConverterProtocol {
         // If cancelled, return before producing outputs.
         guard !isConversionCancelled() else { return ([], []) }
         
-        // Copy images, sample files, and other static assets.
-        do {
-            try outputConsumer.consume(assetsInBundle: bundle)
-        } catch {
-            recordProblem(from: error, in: &conversionProblems, withIdentifier: "assets")
-        }
-        
         // Write various metadata
         if emitDigest {
             do {


Test patch:
diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift
index 134482bba6..91916a0333 100644
--- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift
+++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift
@@ -2456,6 +2456,91 @@ class ConvertActionTests: XCTestCase {
         expectedOutput.assertExist(at: result.outputs[0], fileManager: FileManager.default)
     }
 
+    // Tests that custom templates are injected into the extra index.html files generated for static hosting.
+    func testConvertWithCustomTemplatesForStaticHosting() throws {
+        let info = InfoPlist(displayName: "TestConvertWithCustomTemplatesForStaticHosting", identifier: "com.test.example")
+        let index = TextFile(name: "index.html", utf8Content: """
+        <!DOCTYPE html>
+        <html lang="en">
+            <head>
+                <title>Test</title>
+            </head>
+            <body data-color-scheme="auto"><p>test for custom templates in static hosting</p></body>
+        </html>
+        """)
+        let template = Folder(name: "template", content: [index])
+        let header = TextFile(name: "header.html", utf8Content: """
+        <header>custom text for header</header>
+        """)
+        let footer = TextFile(name: "footer.html", utf8Content: """
+        <footer>custom text for footer</footer>
+        """)
+
+        // Adding this page will generate a file named:
+        // /documentation/testconvertwithcustomtemplatesforstatichosting/index.html
+        // ...which should have the custom header/footer if they're propagated correctly.
+        let technologyPage = TextFile(name: "TestConvertWithCustomTemplatesForStaticHosting.md", utf8Content: """
+        # TestConvertWithCustomTemplatesForStaticHosting
+
+        @Metadata {
+            @TechnologyRoot
+        }
+
+        An abstract.
+
+        ## Overview
+
+        Text for a paragraph.
+        """)
+        let bundle = Folder(name: "TestConvertWithCustomTemplatesForStaticHosting.docc", content: [
+            info,
+            header,
+            footer,
+            technologyPage
+        ])
+
+        let tempURL = try createTemporaryDirectory()
+        let targetURL = tempURL.appendingPathComponent("target", isDirectory: true)
+
+        let bundleURL = try bundle.write(inside: tempURL)
+        let templateURL = try template.write(inside: tempURL)
+
+        let dataProvider = try LocalFileSystemDataProvider(rootURL: bundleURL)
+
+        var action = try ConvertAction(
+            documentationBundleURL: bundleURL,
+            outOfProcessResolver: nil,
+            analyze: false,
+            targetDirectory: targetURL,
+            htmlTemplateDirectory: templateURL,
+            emitDigest: false,
+            currentPlatforms: nil,
+            dataProvider: dataProvider,
+            fileManager: FileManager.default,
+            temporaryDirectory: createTemporaryDirectory(),
+            experimentalEnableCustomTemplates: true,
+            transformForStaticHosting: true
+        )
+        let result = try action.perform(logHandle: .standardOutput)
+
+        // The custom template contents should be wrapped in <template> tags and
+        // prepended to the <body>
+        let expectedIndex = TextFile(name: "index.html", utf8Content: """
+        <!DOCTYPE html>
+        <html lang="en">
+            <head>
+                <title>Test</title>
+            </head>
+            <body data-color-scheme="auto"><template id="custom-footer">\(footer.utf8Content)</template><template id="custom-header">\(header.utf8Content)</template><p>test for custom templates in static hosting</p></body>
+        </html>
+        """)
+        
+        let expectedTechnologyFolder = Folder(name: "TestConvertWithCustomTemplatesForStaticHosting".lowercased(), content: [expectedIndex])
+        let expectedDocsFolder = Folder(name: "documentation", content: [expectedTechnologyFolder])
+        let expectedOutput = Folder(name: ".docc-build", content: [expectedDocsFolder])
+        expectedOutput.assertExist(at: result.outputs[0], fileManager: FileManager.default)
+    }
+
     func testConvertWithThemeSettings() throws {
         let info = InfoPlist(displayName: "TestConvertWithThemeSettings", identifier: "com.test.example")
         let index = TextFile(name: "index.html", utf8Content: """