From 82bcf51b5f852b2251465eeb0da6e415bdebc263 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Sat, 22 Jul 2023 11:07:36 -0700 Subject: [PATCH] SwiftDocC: use "portable" paths for file names Windows restricts a CharacterSet from use in the file name. Replace that set with `_`. This requires an associated change in the DocC renderer to perform the substitution when converting the URL to a file path. --- Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift | 8 +++++++- Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift | 2 +- Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift | 6 +++--- .../DocumentationContext/DocumentationContextTests.swift | 8 ++++---- .../LinkTargets/LinkDestinationSummaryTests.swift | 4 ++-- .../Test Resources/TestBundle-RenderIndex.json | 4 ++-- Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift | 2 +- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift b/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift index 850489607b..abd8d71dc3 100644 --- a/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift +++ b/Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift @@ -194,7 +194,13 @@ public struct NodeURLGenerator { isURLModified = true name = "'\(name)" } - + + let components = name.components(separatedBy: ["<", ">", ":", "\"", "/", "\\", "|", "?", "*"]) + if components.count > 1 { + isURLModified = true + name = components.joined(separator: "_") + } + // Shorten path components that are too long. // Take the first 240 chars and append a checksum on the *complete* string. if name.count >= pathComponentLengthLimit { diff --git a/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift b/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift index 7f61fefad7..5f8114960b 100644 --- a/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift +++ b/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift @@ -706,7 +706,7 @@ Root XCTAssertEqual(navigatorIndex.path(for: 4), "/tutorials/testoverview") XCTAssertEqual(navigatorIndex.path(for: 9), "/documentation/fillintroduced/maccatalystonlydeprecated()") XCTAssertEqual(navigatorIndex.path(for: 10), "/documentation/fillintroduced/maccatalystonlyintroduced()") - XCTAssertEqual(navigatorIndex.path(for: 21), "/documentation/mykit/globalfunction(_:considering:)") + XCTAssertEqual(navigatorIndex.path(for: 21), "/documentation/mykit/globalfunction(__considering_)") XCTAssertEqual(navigatorIndex.path(for: 23), "/documentation/sidekit/uncuratedclass/angle") assertUniqueIDs(node: navigatorIndex.navigatorTree.root) diff --git a/Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift b/Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift index 421ff705ac..49d2c6ff25 100644 --- a/Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift +++ b/Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift @@ -96,7 +96,7 @@ final class RenderIndexTests: XCTestCase { "type": "groupMarker" }, { - "path": "/documentation/mixedlanguageframework/bar/mystringfunction(_:)", + "path": "/documentation/mixedlanguageframework/bar/mystringfunction(__)", "title": "myStringFunction:error: (navigator title)", "type": "method", "children": [ @@ -324,7 +324,7 @@ final class RenderIndexTests: XCTestCase { }, { "title": "class func myStringFunction(String) throws -> String", - "path": "/documentation/mixedlanguageframework/bar/mystringfunction(_:)", + "path": "/documentation/mixedlanguageframework/bar/mystringfunction(__)", "type": "method" } ] @@ -485,7 +485,7 @@ final class RenderIndexTests: XCTestCase { "type": "groupMarker" }, { - "path": "\/documentation\/mixedlanguageframework\/foo-swift.struct\/init(rawvalue:)", + "path": "\/documentation\/mixedlanguageframework\/foo-swift.struct\/init(rawvalue_)", "title": "init(rawValue: UInt)", "type": "init" }, diff --git a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift index fe8ab15438..4c9040baf2 100644 --- a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift @@ -474,7 +474,7 @@ class DocumentationContextTests: XCTestCase { Folder(name: "Resources", content: [ // This whitespace and punctuation in this *file name* will be replaced by dashes in its identifier. // No content in this file result in identifiers. - TextFile(name: "Technology file: with - whitespace, and_punctuation.tutorial", utf8Content: """ + TextFile(name: "Technology file_ with - whitespace, and_punctuation.tutorial", utf8Content: """ @Tutorials(name: "Technology Name") { @Intro(title: "Intro Title") { @Video(source: introvideo.mp4, poster: introposter.png) @@ -510,10 +510,10 @@ class DocumentationContextTests: XCTestCase { let identifierPaths = context.knownIdentifiers.map { $0.path }.sorted(by: { lhs, rhs in lhs.count < rhs.count }) XCTAssertEqual(identifierPaths, [ // From the two file names - "/tutorials/Technology-file:-with---whitespace,-and_punctuation", + "/tutorials/Technology-file_-with---whitespace,-and_punctuation", // From the volume's title and the chapter's names, appended to their technology's identifier - "/tutorials/Technology-file:-with---whitespace,-and_punctuation/Volume_Section-Title:-with---various!-whitespace,-and/punctuation", - "/tutorials/Technology-file:-with---whitespace,-and_punctuation/Volume_Section-Title:-with---various!-whitespace,-and/punctuation/Chapter_Title:-with---various!-whitespace,-and/punctuation" + "/tutorials/Technology-file_-with---whitespace,-and_punctuation/Volume_Section-Title:-with---various!-whitespace,-and/punctuation", + "/tutorials/Technology-file_-with---whitespace,-and_punctuation/Volume_Section-Title:-with---various!-whitespace,-and/punctuation/Chapter_Title:-with---various!-whitespace,-and/punctuation" ]) } diff --git a/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift b/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift index d5c759bf83..ed726fc8e3 100644 --- a/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift +++ b/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift @@ -276,7 +276,7 @@ class ExternalLinkableTests: XCTestCase { let summary = node.externallyLinkableElementSummaries(context: context, renderNode: renderNode)[0] XCTAssertEqual(summary.title, "globalFunction(_:considering:)") - XCTAssertEqual(summary.relativePresentationURL.absoluteString, "/documentation/mykit/globalfunction(_:considering:)") + XCTAssertEqual(summary.relativePresentationURL.absoluteString, "/documentation/mykit/globalfunction(__considering_)") XCTAssertEqual(summary.referenceURL.absoluteString, "doc://org.swift.docc.example/documentation/MyKit/globalFunction(_:considering:)") XCTAssertEqual(summary.language, .swift) XCTAssertEqual(summary.kind, .function) @@ -486,7 +486,7 @@ class ExternalLinkableTests: XCTestCase { let summary = node.externallyLinkableElementSummaries(context: context, renderNode: renderNode)[0] XCTAssertEqual(summary.title, "myStringFunction(_:)") - XCTAssertEqual(summary.relativePresentationURL.absoluteString, "/documentation/mixedlanguageframework/bar/mystringfunction(_:)") + XCTAssertEqual(summary.relativePresentationURL.absoluteString, "/documentation/mixedlanguageframework/bar/mystringfunction(__)") XCTAssertEqual(summary.referenceURL.absoluteString, "doc://org.swift.MixedLanguageFramework/documentation/MixedLanguageFramework/Bar/myStringFunction(_:)") XCTAssertEqual(summary.language, .swift) XCTAssertEqual(summary.kind, .typeMethod) diff --git a/Tests/SwiftDocCTests/Test Resources/TestBundle-RenderIndex.json b/Tests/SwiftDocCTests/Test Resources/TestBundle-RenderIndex.json index 0350577277..3af4abf29b 100644 --- a/Tests/SwiftDocCTests/Test Resources/TestBundle-RenderIndex.json +++ b/Tests/SwiftDocCTests/Test Resources/TestBundle-RenderIndex.json @@ -614,7 +614,7 @@ "type" : "groupMarker" }, { - "path" : "\/documentation\/mykit\/globalfunction(_:considering:)", + "path" : "\/documentation\/mykit\/globalfunction(__considering_)", "title" : "func globalFunction(Data, considering: Int)", "type" : "func" }, @@ -638,7 +638,7 @@ "type" : "groupMarker" }, { - "path" : "\/documentation\/sidekit\/sideclass\/value(_:)", + "path" : "\/documentation\/sidekit\/sideclass\/value(__)", "title" : "case Value(Int)", "type" : "case" }, diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift index cd9d08e3d5..a671ca971e 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -324,7 +324,7 @@ class ConvertActionTests: XCTestCase { "/output/data/documentation/mykit/myclass/init()-3743d.json", "/output/data/documentation/mykit/myclass/myfunction().json", "/output/data/documentation/mykit/myprotocol.json", - "/output/data/documentation/mykit/globalfunction(_:considering:).json", + "/output/data/documentation/mykit/globalfunction(__considering_).json", ].sorted()) let myKitNodeData = try XCTUnwrap(outputData["/output/data/documentation/mykit.json"])