Skip to content

Commit 42ec76f

Browse files
committed
Register references resolved by fallback resolvers (#135)
When resolving a link via a fallback resolver (i.e., a resolver that resolves additional content for the bundle's identifier), register the reference in the documentation context so that it can be looked up via its absolute URL string. This is important for subsequent link resolution requests, in order for the reference to be looked up in the context rather than getting resolved again. rdar://91545038
1 parent 365ff4e commit 42ec76f

File tree

3 files changed

+329
-1
lines changed

3 files changed

+329
-1
lines changed

Sources/SwiftDocC/Infrastructure/DocumentationContext.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1383,12 +1383,16 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
13831383
referencesIndex.removeAll()
13841384
referencesIndex.reserveCapacity(knownIdentifiers.count)
13851385
for reference in knownIdentifiers {
1386-
referencesIndex[reference.absoluteString] = reference
1386+
registerReference(reference)
13871387
}
13881388

13891389
return (moduleReferences: Set(moduleReferences.values), urlHierarchy: symbolsURLHierarchy)
13901390
}
13911391
}
1392+
1393+
private func registerReference(_ resolvedReference: ResolvedTopicReference) {
1394+
referencesIndex[resolvedReference.absoluteString] = resolvedReference
1395+
}
13921396

13931397
private func shouldContinueRegistration() throws {
13941398
guard isRegistrationEnabled.sync({ $0 }) else {
@@ -2607,6 +2611,11 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {
26072611

26082612
if case .success(let resolvedReference) = reference {
26092613
cacheReference(resolvedReference, withKey: ResolvedTopicReference.cacheIdentifier(unresolvedReference, fromSymbolLink: isCurrentlyResolvingSymbolLink, in: parent))
2614+
2615+
// Register the resolved reference in the context so that it can be looked up via its absolute
2616+
// path. We only do this for in-bundle content, and since we've just resolved an in-bundle link,
2617+
// we register the reference.
2618+
registerReference(resolvedReference)
26102619
return .success(resolvedReference)
26112620
}
26122621
}

Tests/SwiftDocCTests/DocumentationService/ConvertService/ConvertServiceTests.swift

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,112 @@ class ConvertServiceTests: XCTestCase {
11871187
}
11881188
}
11891189

1190+
func testConvertTopLevelSymbolWithLinkResolving() throws {
1191+
let symbolGraphFile = Bundle.module.url(
1192+
forResource: "one-symbol-top-level",
1193+
withExtension: "symbols.json",
1194+
subdirectory: "Test Resources"
1195+
)!
1196+
1197+
let symbolGraph = try Data(contentsOf: symbolGraphFile)
1198+
1199+
let request = ConvertRequest(
1200+
bundleInfo: DocumentationBundle.Info(
1201+
displayName: "TestBundle",
1202+
identifier: "org.swift.example",
1203+
version: "1.0.0"
1204+
),
1205+
externalIDsToConvert: ["s:32MyKit3FooV"],
1206+
documentPathsToConvert: [],
1207+
symbolGraphs: [symbolGraph],
1208+
markupFiles: [],
1209+
miscResourceURLs: []
1210+
)
1211+
1212+
let server = DocumentationServer()
1213+
1214+
let mockLinkResolvingService = LinkResolvingService { message in
1215+
do {
1216+
let payload = try XCTUnwrap(message.payload)
1217+
let request = try JSONDecoder()
1218+
.decode(
1219+
ConvertRequestContextWrapper<OutOfProcessReferenceResolver.Request>.self,
1220+
from: payload
1221+
)
1222+
1223+
let errorResponse = DocumentationServer.Message(
1224+
type: "resolve-reference-response",
1225+
payload: try JSONEncoder().encode(
1226+
OutOfProcessReferenceResolver.Response
1227+
.errorMessage("Unable to resolve reference.")
1228+
)
1229+
)
1230+
1231+
switch request.payload {
1232+
case .topic(let url):
1233+
let resolvableBarURL = URL(
1234+
string: "doc://org.swift.example/documentation/MyKit/Foo/bar()"
1235+
)!
1236+
1237+
if url == resolvableBarURL {
1238+
let testSymbolInformationResponse = OutOfProcessReferenceResolver
1239+
.ResolvedInformation(
1240+
kind: .init(
1241+
name: "bar()",
1242+
id: "org.swift.docc.kind.method",
1243+
isSymbol: true
1244+
),
1245+
url: resolvableBarURL,
1246+
title: "bar()",
1247+
abstract: "",
1248+
language: .init(name: "Swift", id: "swift"),
1249+
availableLanguages: [],
1250+
platforms: [],
1251+
declarationFragments: nil
1252+
)
1253+
1254+
let payloadData = OutOfProcessReferenceResolver.Response
1255+
.resolvedInformation(testSymbolInformationResponse)
1256+
1257+
return DocumentationServer.Message(
1258+
type: "resolve-reference-response",
1259+
payload: try JSONEncoder().encode(payloadData)
1260+
)
1261+
} else {
1262+
return errorResponse
1263+
}
1264+
default:
1265+
return errorResponse
1266+
}
1267+
} catch {
1268+
XCTFail(error.localizedDescription)
1269+
return nil
1270+
}
1271+
}
1272+
1273+
server.register(service: mockLinkResolvingService)
1274+
1275+
try processAndAssert(request: request, linkResolvingServer: server) { message in
1276+
let renderNodes = try JSONDecoder().decode(
1277+
ConvertResponse.self,
1278+
from: XCTUnwrap(message.payload)
1279+
).renderNodes
1280+
1281+
XCTAssertEqual(renderNodes.count, 1)
1282+
let data = try XCTUnwrap(renderNodes.first)
1283+
let renderNode = try JSONDecoder().decode(RenderNode.self, from: data)
1284+
1285+
XCTAssertEqual(
1286+
Set(renderNode.references.keys),
1287+
[
1288+
"doc://org.swift.example/documentation/MyKit",
1289+
"doc://org.swift.example/documentation/MyKit/Foo",
1290+
"doc://org.swift.example/documentation/MyKit/Foo/bar()",
1291+
]
1292+
)
1293+
}
1294+
}
1295+
11901296
func testOrderOfLinkResolutionRequestsForDocLink() throws {
11911297
let symbolGraphFile = try XCTUnwrap(
11921298
Bundle.module.url(
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
{
2+
"metadata": {
3+
"formatVersion": {
4+
"major": 0,
5+
"minor": 5,
6+
"patch": 3
7+
},
8+
"generator": "Apple Swift version 5.7 (swiftlang-5.7.0.101.10 clang-1400.0.10.4.2)"
9+
},
10+
"module": {
11+
"name": "MyKit",
12+
"platform": {
13+
"architecture": "x86_64",
14+
"vendor": "apple",
15+
"operatingSystem": {
16+
"name": "macosx",
17+
"minimumVersion": {
18+
"major": 10,
19+
"minor": 10,
20+
"patch": 0
21+
}
22+
}
23+
}
24+
},
25+
"symbols": [
26+
{
27+
"kind": {
28+
"identifier": "swift.struct",
29+
"displayName": "Structure"
30+
},
31+
"identifier": {
32+
"precise": "s:32MyKit3FooV",
33+
"interfaceLanguage": "swift"
34+
},
35+
"pathComponents": [
36+
"Foo"
37+
],
38+
"names": {
39+
"title": "Foo"
40+
},
41+
"docComment": {
42+
"lines": [
43+
{
44+
"range": {
45+
"start": {
46+
"line": 0,
47+
"character": 4
48+
},
49+
"end": {
50+
"line": 0,
51+
"character": 15
52+
}
53+
},
54+
"text": "Foo"
55+
},
56+
{
57+
"range": {
58+
"start": {
59+
"line": 1,
60+
"character": 3
61+
},
62+
"end": {
63+
"line": 1,
64+
"character": 3
65+
}
66+
},
67+
"text": ""
68+
},
69+
{
70+
"range": {
71+
"start": {
72+
"line": 2,
73+
"character": 4
74+
},
75+
"end": {
76+
"line": 2,
77+
"character": 39
78+
}
79+
},
80+
"text": "All of these links should resolve:"
81+
},
82+
{
83+
"range": {
84+
"start": {
85+
"line": 3,
86+
"character": 3
87+
},
88+
"end": {
89+
"line": 3,
90+
"character": 3
91+
}
92+
},
93+
"text": ""
94+
},
95+
{
96+
"range": {
97+
"start": {
98+
"line": 4,
99+
"character": 4
100+
},
101+
"end": {
102+
"line": 4,
103+
"character": 13
104+
}
105+
},
106+
"text": "``bar()``"
107+
},
108+
{
109+
"range": {
110+
"start": {
111+
"line": 5,
112+
"character": 3
113+
},
114+
"end": {
115+
"line": 5,
116+
"character": 3
117+
}
118+
},
119+
"text": ""
120+
},
121+
{
122+
"range": {
123+
"start": {
124+
"line": 6,
125+
"character": 4
126+
},
127+
"end": {
128+
"line": 6,
129+
"character": 17
130+
}
131+
},
132+
"text": "``Foo/bar()``"
133+
},
134+
{
135+
"range": {
136+
"start": {
137+
"line": 7,
138+
"character": 3
139+
},
140+
"end": {
141+
"line": 7,
142+
"character": 3
143+
}
144+
},
145+
"text": ""
146+
},
147+
{
148+
"range": {
149+
"start": {
150+
"line": 8,
151+
"character": 4
152+
},
153+
"end": {
154+
"line": 8,
155+
"character": 22
156+
}
157+
},
158+
"text": "``Foo/otherBar()``"
159+
},
160+
{
161+
"range": {
162+
"start": {
163+
"line": 9,
164+
"character": 3
165+
},
166+
"end": {
167+
"line": 9,
168+
"character": 3
169+
}
170+
},
171+
"text": ""
172+
},
173+
{
174+
"range": {
175+
"start": {
176+
"line": 10,
177+
"character": 4
178+
},
179+
"end": {
180+
"line": 10,
181+
"character": 50
182+
}
183+
},
184+
"text": "``MyKit/Foo/bar()``"
185+
}
186+
]
187+
},
188+
"declarationFragments": [
189+
{
190+
"kind": "keyword",
191+
"spelling": "struct"
192+
},
193+
{
194+
"kind": "text",
195+
"spelling": " "
196+
},
197+
{
198+
"kind": "identifier",
199+
"spelling": "Foo"
200+
}
201+
],
202+
"accessLevel": "public",
203+
"location": {
204+
"uri": "file:///tmp/Downloads/MyKit/MyKit.swift",
205+
"position": {
206+
"line": 11,
207+
"character": 14
208+
}
209+
}
210+
}
211+
],
212+
"relationships": []
213+
}

0 commit comments

Comments
 (0)