Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit 9d85789

Browse files
compnerdmattt
andauthored
perform some path sanitization over the generated names (#258)
* perform some path sanitization over the generated names The current scheme for the file generation uses the function label, which uses ':' as a parameter separator. However, this character is not valid on all file systems. This results in partial content generation on Windows. Add a sanitization step which replaces "invalid" characters with `_` instead. This does not impact the rendering, only the filenames and the generated URL references between the pages. With this, we can generate and link function documentation on Windows. * Apply suggestion from code review Co-authored-by: Mattt <[email protected]>
1 parent e172d3d commit 9d85789

File tree

3 files changed

+22
-12
lines changed

3 files changed

+22
-12
lines changed

Sources/SwiftDoc/Helpers.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,20 @@ public func path(for symbol: Symbol, with baseURL: String) -> String {
1414
}
1515

1616
public func path(for identifier: CustomStringConvertible, with baseURL: String) -> String {
17-
let url = URL(string: baseURL)?.appendingPathComponent("\(identifier)") ?? URL(string: "\(identifier)")
17+
let tail: String = path(for: "\(identifier)")
18+
let url = URL(string: baseURL)?.appendingPathComponent(tail) ?? URL(string: tail)
1819
guard let string = url?.absoluteString else {
1920
fatalError("Unable to construct path for \(identifier) with baseURL \(baseURL)")
2021
}
2122

2223
return string
2324
}
25+
26+
private let reservedCharacters: CharacterSet = [
27+
// Windows Reserved Characters
28+
"<", ">", ":", "\"", "/", "\\", "|", "?", "*",
29+
]
30+
31+
public func path(for identifier: String) -> String {
32+
return identifier.components(separatedBy: reservedCharacters).joined(separator: "_")
33+
}

Sources/swift-doc/Subcommands/Generate.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ extension SwiftDoc {
134134
let filename: String
135135
switch format {
136136
case .commonmark:
137-
filename = "\($0.key).md"
137+
filename = "\(path(for: $0.key)).md"
138138
case .html where $0.key == "Home":
139139
filename = "index.html"
140140
case .html:
141-
filename = "\($0.key)/index.html"
141+
filename = "\(path(for: $0.key))/index.html"
142142
}
143143

144144
let url = outputDirectoryURL.appendingPathComponent(filename)

Tests/SwiftDocTests/PathTests.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,42 @@ final class PathTests: XCTestCase {
66
func testEmptyBaseURL() {
77
XCTAssertEqual(path(for: "Class", with: ""), "Class")
88

9-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: ""), "(lhs:rhs:)")
9+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: ""), "(lhs_rhs_)")
1010
}
1111

1212
func testRootDirectoryBaseURL() {
1313
XCTAssertEqual(path(for: "Class", with: "/"), "/Class")
1414

15-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "/"), "/(lhs:rhs:)")
15+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "/"), "/(lhs_rhs_)")
1616
}
1717

1818
func testCurrentDirectoryBaseURL() {
1919
XCTAssertEqual(path(for: "Class", with: "./"), "./Class")
2020

21-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "./"), "./(lhs:rhs:)")
21+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "./"), "./(lhs_rhs_)")
2222
}
2323

2424
func testNestedSubdirectoryBaseURL() {
2525
XCTAssertEqual(path(for: "Class", with: "/path/to/directory"), "/path/to/directory/Class")
2626
XCTAssertEqual(path(for: "Class", with: "/path/to/directory/"), "/path/to/directory/Class")
2727

28-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "/path/to/directory"), "/path/to/directory/(lhs:rhs:)")
29-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "/path/to/directory/"), "/path/to/directory/(lhs:rhs:)")
28+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "/path/to/directory"), "/path/to/directory/(lhs_rhs_)")
29+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "/path/to/directory/"), "/path/to/directory/(lhs_rhs_)")
3030
}
3131

3232
func testDomainBaseURL() {
3333
XCTAssertEqual(path(for: "Class", with: "https://example.com"), "https://example.com/Class")
3434
XCTAssertEqual(path(for: "Class", with: "https://example.com/"), "https://example.com/Class")
3535

36-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com"), "https://example.com/(lhs:rhs:)")
37-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com/"), "https://example.com/(lhs:rhs:)")
36+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com"), "https://example.com/(lhs_rhs_)")
37+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com/"), "https://example.com/(lhs_rhs_)")
3838
}
3939

4040
func testDomainSubdirectoryBaseURL() {
4141
XCTAssertEqual(path(for: "Class", with: "https://example.com/docs"), "https://example.com/docs/Class")
4242
XCTAssertEqual(path(for: "Class", with: "https://example.com/docs/"), "https://example.com/docs/Class")
4343

44-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com/docs"), "https://example.com/docs/(lhs:rhs:)")
45-
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com/docs/"), "https://example.com/docs/(lhs:rhs:)")
44+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com/docs"), "https://example.com/docs/(lhs_rhs_)")
45+
XCTAssertEqual(path(for: "(lhs:rhs:)", with: "https://example.com/docs/"), "https://example.com/docs/(lhs_rhs_)")
4646
}
4747
}

0 commit comments

Comments
 (0)