Skip to content

Commit 06431a8

Browse files
authored
Allow anchor <doc:#heading> within same article (#652)
1 parent d2bf7d6 commit 06431a8

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy.swift

+8-2
Original file line numberDiff line numberDiff line change
@@ -764,10 +764,16 @@ extension PathHierarchy {
764764
let isAbsolute = path.first == "/"
765765
|| String(components.first ?? "") == NodeURLGenerator.Path.documentationFolderName
766766
|| String(components.first ?? "") == NodeURLGenerator.Path.tutorialsFolderName
767-
767+
768+
// If there is a # character in the last component, split that into two components
768769
if let hashIndex = components.last?.firstIndex(of: "#") {
769770
let last = components.removeLast()
770-
components.append(last[..<hashIndex])
771+
// Allow anrhor-only links where there's nothing before #.
772+
// In case the pre-# part is empty, and we're omitting empty components, don't add it in.
773+
let pathName = last[..<hashIndex]
774+
if !pathName.isEmpty || !omittingEmptyComponents {
775+
components.append(pathName)
776+
}
771777

772778
let fragment = String(last[hashIndex...].dropFirst())
773779
return (components.map(Self.parse(pathComponent:)) + [PathComponent(full: fragment, name: fragment, kind: nil, hash: nil)], isAbsolute)

Tests/SwiftDocCTests/Infrastructure/PathHierarchyTests.swift

+25
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,30 @@ class PathHierarchyTests: XCTestCase {
11331133
XCTAssertNil(articleNode.symbol, "General documentation link find the article")
11341134
}
11351135

1136+
func testArticleSelfAnchorLinks() throws {
1137+
try XCTSkipUnless(LinkResolutionMigrationConfiguration.shouldUseHierarchyBasedLinkResolver)
1138+
let (_, _, context) = try testBundleAndContext(copying: "MixedLanguageFramework") { url in
1139+
try """
1140+
# ArticleWithHeading
1141+
1142+
## TestTargetHeading
1143+
1144+
This article has the same path as a symbol. See also:
1145+
- <doc:TestTargetHeading>
1146+
- <doc:#TestTargetHeading>
1147+
1148+
""".write(to: url.appendingPathComponent("ArticleWithHeading.md"), atomically: true, encoding: .utf8)
1149+
}
1150+
1151+
let tree = try XCTUnwrap(context.hierarchyBasedLinkResolver?.pathHierarchy)
1152+
let articleNode = try tree.findNode(path: "/MixedLanguageFramework/ArticleWithHeading", onlyFindSymbols: false)
1153+
1154+
let linkNode = try tree.find(path: "TestTargetHeading", parent: articleNode.identifier, onlyFindSymbols: false)
1155+
let anchorLinkNode = try tree.find(path: "#TestTargetHeading", parent: articleNode.identifier, onlyFindSymbols: false)
1156+
XCTAssertNotNil(linkNode)
1157+
XCTAssertNotNil(anchorLinkNode)
1158+
}
1159+
11361160
func testOverloadedSymbols() throws {
11371161
try XCTSkipUnless(LinkResolutionMigrationConfiguration.shouldUseHierarchyBasedLinkResolver)
11381162
let (_, context) = try testBundleAndContext(named: "OverloadedSymbols")
@@ -1555,6 +1579,7 @@ class PathHierarchyTests: XCTestCase {
15551579
assertParsedPathComponents("first/", [("first", nil, nil)])
15561580
assertParsedPathComponents("first//second", [("first", nil, nil), ("second", nil, nil)])
15571581
assertParsedPathComponents("first/second#third", [("first", nil, nil), ("second", nil, nil), ("third", nil, nil)])
1582+
assertParsedPathComponents("#first", [("first", nil, nil)])
15581583

15591584
// Check disambiguation
15601585
assertParsedPathComponents("path-hash", [("path", nil, "hash")])

0 commit comments

Comments
 (0)