From 74fbe3f25ad02782e1fcafbb2c5e60431e6f3154 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 71efab8a1a..c1bb971236 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 f868ae72af..e7fe7c2fa4 100644 --- a/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift +++ b/Tests/SwiftDocCTests/Indexing/NavigatorIndexTests.swift @@ -891,7 +891,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 42d9f37e9e..e494cc5022 100644 --- a/Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift +++ b/Tests/SwiftDocCTests/Indexing/RenderIndexTests.swift @@ -99,7 +99,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": [ @@ -327,7 +327,7 @@ final class RenderIndexTests: XCTestCase { }, { "title": "class func myStringFunction(String) throws -> String", - "path": "/documentation/mixedlanguageframework/bar/mystringfunction(_:)", + "path": "/documentation/mixedlanguageframework/bar/mystringfunction(__)", "type": "method" } ] @@ -488,7 +488,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 2f5a97a44e..1d1783beb4 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 c2121895e7..337a4d046c 100644 --- a/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift +++ b/Tests/SwiftDocCTests/LinkTargets/LinkDestinationSummaryTests.swift @@ -287,7 +287,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) @@ -508,7 +508,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 70d3d01c43..5338620f81 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 125f3c3f75..6f82088097 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -330,7 +330,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"])