Skip to content

Populate symbol kind in external render nodes #1251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

anferbui
Copy link
Contributor

Bug/issue #, if applicable: N/A

Summary

Fixes the navigator page type for external render nodes such that it takes into account the kind of symbol of the node.

In order to properly determine the navigator page type for a symbol, we need to know its symbol kind:

/// Returns the type of page for the render node.
func navigatorPageType() -> NavigatorIndex.PageType {
// This is a workaround to support plist keys.
switch metadata.roleHeading?.lowercased() {
case "property list key": return .propertyListKey
case "property list key reference": return .propertyListKeyReference
default: break
}
switch kind {
case .article: return metadata.role.map { .init(role: $0) }
?? .article
case .tutorial: return .tutorial
case .section: return .section
case .overview: return .overview
case .symbol: return metadata.symbolKind.map { .init(symbolKind: $0) }
?? metadata.role.map { .init(role: $0) }
?? .symbol
}
}
}

However, the symbol kind was not available for external nodes and all items were showing as their generic role, e.g. "article" or "symbol".

This PR adds logic to derive an external render node's symbol kind:

  1. Propagating the OutOfProcessReferenceResolver.ResolvedInformation's documentation kind to LinkResolver.ExternalEntity, the type which is used to deal with external entities.
  2. Convert the documentation kind into a symbol kind, following an already existing mapping but in reverse.
  3. Use the symbol kind's rendering identifier to determine the navigator page type, same as for local render nodes.

Navigator comparison (using swift-docc-render):

Before After
Screenshot 2025-07-21 at 14 02 22 Screenshot 2025-07-21 at 13 58 13

The navigator icons on the right match the symbol kinds of the external pages.

The navigator index.json shows the correct page type as well:

          {
            "external": true,
            "path": "/resolved/class",
            "title": "Resolved class",
            "type": "class"
          }

Dependencies

N/A.

Testing

Previewed a custom bundle locally which contained different types of external links (module, class, function and article).

  • Verified that they showed the relevant icon in the navigator when using swift-docc-render.
  • Verified that the resulting index.json looked as expected

Steps:

  1. Use example bundle: Example.docc.zip
    • The bundle contains a link resolver executable for resolving external entities
  2. Run DOCC_LINK_RESOLVER_EXECUTABLE=Example.docc/bin/test-data-external-resolver swift run docc preview Example.docc
  3. Verify that the navigator page icons in http://localhost:8080/documentation/article look as expected
  4. Verify that the navigator JSON at Example.docc/.docc-build/index/index.json looks as expected.

Checklist

Make sure you check off the following items. If they cannot be completed, provide a reason.

  • Added tests
  • Ran the ./bin/test script and it succeeded
  • Updated documentation if necessary

anferbui added 3 commits July 21, 2025 10:55
There is a mapping from `SymbolGraph.Symbol.KindIdentifier` to `DocumentationNode.Kind`, but not the other way around; this commit adds one.

For documentation kinds which both map to the same symbol kind, this has been expressed as:
- both documentation kinds are converted to the same symbol kind in `symbolKind(for:)`.
- a specific documentation kind is chosen as the default mapping in `kind(forKind:)`

For example, for `DocumentationNode.Kind. typeConstant` [1]:
- both `symbolKind(for: .typeConstant)` and `symbolKind(for: .typeProperty)` return `.typeProperty`
- `kind(forKind: .typeProperty)` returns `.typeProperty`

This function will be used to map and external entity's documentation kind to a symbol kind, so that that information can be populated as part of the navigator.

## Verification:

This has been verified by testing the round trip conversion of all symbol kinds, and all documentation kinds which are symbols.

[1]: https://github.com/swiftlang/swift-docc/blob/65aaf926ec079ddbd40f29540d4180a70af99e5e/Sources/SwiftDocC/Model/Kind.swift#L151
The documentation kind is captured as part of the `OutOfProcessReferenceResolver. ResolvedInformation` [1], but it is never propagated upwards to `LinkResolver.ExternalEntity`.

We need access to the documentation kind in order to resolve the symbol kind as part of computing the navigator title. [2]

[1]: https://github.com/swiftlang/swift-docc/blob/65aaf926ec079ddbd40f29540d4180a70af99e5e/Sources/SwiftDocC/Infrastructure/External%20Data/OutOfProcessReferenceResolver.swift#L564-L565
[2]: https://github.com/swiftlang/swift-docc/blob/65aaf926ec079ddbd40f29540d4180a70af99e5e/Sources/SwiftDocC/Indexing/Navigator/RenderNode%2BNavigatorIndex.swift#L163
Derives the symbol kind from the documentation kind of the external render node.

Also updates how the symbol kind is propagated to the navigator metadata, by using `.renderingIdentifier` over `.identifier`, to match the behaviour of local nodes [1].

[1]: https://github.com/swiftlang/swift-docc/blob/65aaf926ec079ddbd40f29540d4180a70af99e5e/Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift#L1300
@anferbui anferbui requested a review from sofiaromorales July 21, 2025 13:44
@anferbui
Copy link
Contributor Author

@swift-ci please test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant