Skip to content
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

[5.9] Process typeDetails information from symbol graphs #530

Merged
merged 2 commits into from
Apr 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"package": "SymbolKit",
"repositoryURL": "https://github.com/apple/swift-docc-symbolkit",
"state": {
"branch": "main",
"revision": "ccbbd881d75d3ca503daf8cf3b5d78adbf647da9",
"branch": "release/5.9",
"revision": "d42e3db1c0f97f4a3be9a4552f7003c2959268d5",
"version": null
}
},
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
.package(name: "swift-markdown", url: "https://github.com/apple/swift-markdown.git", .branch("main")),
.package(name: "CLMDB", url: "https://github.com/apple/swift-lmdb.git", .branch("main")),
.package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "1.0.1")),
.package(name: "SymbolKit", url: "https://github.com/apple/swift-docc-symbolkit", .branch("main")),
.package(name: "SymbolKit", url: "https://github.com/apple/swift-docc-symbolkit", .branch("release/5.9")),
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMinor(from: "1.1.2")),
]

Expand Down
49 changes: 33 additions & 16 deletions Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1741,6 +1741,24 @@ public struct RenderNodeTranslator: SemanticVisitor {
}
}

private mutating func convert_fragments(_ fragments: [SymbolGraph.Symbol.DeclarationFragments.Fragment]) -> [DeclarationRenderSection.Token] {
return fragments.map { token -> DeclarationRenderSection.Token in

// Create a reference if one found
var reference: ResolvedTopicReference?
if let preciseIdentifier = token.preciseIdentifier,
let resolved = self.context.symbolIndex[preciseIdentifier]?.reference {
reference = resolved

// Add relationship to render references
self.collectedTopicReferences.append(resolved)
}

// Add the declaration token
return DeclarationRenderSection.Token(fragment: token, identifier: reference?.absoluteString)
}
}

/// Generate a RenderProperty object from markup content and symbol data.
mutating func createRenderProperty(name: String, contents: [Markup], required: Bool, symbol: SymbolGraph.Symbol?) -> RenderProperty {
let parameterContent = self.visitMarkupContainer(
Expand All @@ -1752,25 +1770,12 @@ public struct RenderNodeTranslator: SemanticVisitor {
var isReadOnly: Bool? = nil
var deprecated: Bool? = nil
var introducedVersion: String? = nil
var typeDetails: [TypeDetails]? = nil

if let symbol = symbol {
// Convert the dictionary key's declaration into section tokens
if let fragments = symbol.declarationFragments {
renderedTokens = fragments.map { token -> DeclarationRenderSection.Token in

// Create a reference if one found
var reference: ResolvedTopicReference?
if let preciseIdentifier = token.preciseIdentifier,
let resolved = self.context.symbolIndex[preciseIdentifier]?.reference {
reference = resolved

// Add relationship to render references
self.collectedTopicReferences.append(resolved)
}

// Add the declaration token
return DeclarationRenderSection.Token(fragment: token, identifier: reference?.absoluteString)
}
renderedTokens = convert_fragments(fragments)
}

// Populate attributes
Expand Down Expand Up @@ -1801,6 +1806,18 @@ public struct RenderNodeTranslator: SemanticVisitor {
if let constraint = symbol.maximumLength {
attributes.append(RenderAttribute.maximumLength(String(constraint)))
}
if let constraint = symbol.typeDetails, constraint.count > 0 {
// Pull out the base-type details.
typeDetails = constraint.filter { $0.baseType != nil }
.map { TypeDetails(baseType: $0.baseType, arrayMode: $0.arrayMode) }
// Pull out the allowed-type declarations.
// If there is only 1 type declaration found, it would be redundant with declaration, so skip it.
let typeDeclarations = constraint.compactMap { $0.fragments }
if typeDeclarations.count > 1 {
let allowedTypes = typeDeclarations.map { convert_fragments($0) }
attributes.append(RenderAttribute.allowedTypes(allowedTypes))
}
}

// Extract the availability information
if let availabilityItems = symbol.availability, availabilityItems.count > 0 {
Expand All @@ -1818,7 +1835,7 @@ public struct RenderNodeTranslator: SemanticVisitor {
return RenderProperty(
name: name,
type: renderedTokens ?? [],
typeDetails: nil,
typeDetails: typeDetails,
content: parameterContent,
attributes: attributes,
mimeType: symbol?.httpMediaType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ class SemaToRenderNodeDictionaryDataTests: XCTestCase {
let expectedPageUSRs: Set<String> = Set(expectedPageUSRsAndLangs.keys)

let expectedNonpageUSRs: Set<String> = [
// Name string type - ``Name``:
// Name string field - ``name``:
"data:test:Artist@name",

// Genre string type - ``Genre``:
// Genre string field - ``genre``:
"data:test:Artist@genre",

// Age integer type - ``Age``:
// Month of birth string field - ``monthOfBirth``:
"data:test:Artist@monthOfBirth",

// Age integer field - ``age``:
"data:test:Artist@age",
]

Expand Down Expand Up @@ -179,7 +182,7 @@ class SemaToRenderNodeDictionaryDataTests: XCTestCase {
}

XCTAssertEqual(propertiesSection.kind, .properties)
XCTAssertEqual(propertiesSection.items.count, 3)
XCTAssertEqual(propertiesSection.items.count, 4)

let ageProperty = propertiesSection.items[0]
XCTAssertEqual(ageProperty.name, "age")
Expand All @@ -193,9 +196,61 @@ class SemaToRenderNodeDictionaryDataTests: XCTestCase {
attributeTitles = genreProperty.attributes?.map{$0.title.lowercased()}.sorted() ?? []
XCTAssertEqual(attributeTitles, ["default value", "possible values"])

let nameProperty = propertiesSection.items[2]
let monthProperty = propertiesSection.items[2]
XCTAssertEqual(monthProperty.name, "monthOfBirth")
XCTAssertNotNil(monthProperty.typeDetails)
if let details = monthProperty.typeDetails {
XCTAssertEqual(details.count, 2)
XCTAssertEqual(details[0].baseType, "integer")
XCTAssertEqual(details[1].baseType, "string")
}
attributeTitles = monthProperty.attributes?.map{$0.title.lowercased()}.sorted() ?? []
XCTAssertEqual(attributeTitles, ["possible types"])
monthProperty.attributes?.forEach { attribute in
if case let .allowedTypes(decls) = attribute {
XCTAssertEqual(decls.count, 2)
XCTAssertEqual(decls[0][0].text, "integer")
XCTAssertEqual(decls[1][0].text, "string")
}
}

let nameProperty = propertiesSection.items[3]
XCTAssertEqual(nameProperty.name, "name")
XCTAssertTrue(nameProperty.required ?? false)
XCTAssert((nameProperty.attributes ?? []).isEmpty)
}

func testTypeRenderNodeHasExpectedContent() throws {
let outputConsumer = try renderNodeConsumer(for: "DictionaryData")
let genreRenderNode = try outputConsumer.renderNode(withIdentifier: "data:test:Genre")

print(genreRenderNode)
assertExpectedContent(
genreRenderNode,
sourceLanguage: "data",
symbolKind: "typealias",
title: "Genre",
navigatorTitle: nil,
abstract: nil,
declarationTokens: [
"string ",
"Genre"
],
discussionSection: nil,
topicSectionIdentifiers: [],
referenceTitles: [
"Artist",
"DictionaryData",
"Genre",
],
referenceFragments: [
"object Artist",
"string Genre",
],
failureMessage: { fieldName in
"'Genre' symbol has unexpected content for '\(fieldName)'."
}
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
"target": "data:test:Artist",
"targetFallback": null
},
{
"kind": "optionalMemberOf",
"source": "data:test:Artist@monthOfBirth",
"target": "data:test:Artist",
"targetFallback": null
},
{
"kind": "memberOf",
"source": "data:test:Artist@name",
Expand Down Expand Up @@ -163,6 +169,50 @@
"genre"
]
},
{
"accessLevel": "public",
"declarationFragments": [
{
"kind": "text",
"spelling": "*"
}
],
"identifier": {
"interfaceLanguage": "data",
"precise": "data:test:Artist@monthOfBirth"
},
"kind": {
"displayName": "Dictionary Key",
"identifier": "dictionaryKey"
},
"names": {
"title": "monthOfBirth"
},
"pathComponents": [
"Artist",
"monthOfBirth"
],
"typeDetails": [
{
"baseType": "integer",
"fragments": [
{
"kind": "text",
"spelling": "integer"
}
]
},
{
"baseType": "string",
"fragments": [
{
"kind": "text",
"spelling": "string"
}
]
}
]
},
{
"accessLevel": "public",
"declarationFragments": [
Expand Down Expand Up @@ -192,7 +242,11 @@
"declarationFragments": [
{
"kind": "text",
"spelling": "string Genre"
"spelling": "string "
},
{
"kind": "identifier",
"spelling": "Genre"
}
],
"identifier": {
Expand All @@ -218,6 +272,11 @@
},
"pathComponents": [
"Genre"
],
"typeDetails": [
{
"baseType": "string",
}
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftDocCTests/XCTestCase+AssertingTestData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extension XCTestCase {
symbolKind expectedSymbolKind: String? = nil,
title expectedTitle: String,
navigatorTitle expectedNavigatorTitle: String?,
abstract expectedAbstract: String,
abstract expectedAbstract: String?,
declarationTokens expectedDeclarationTokens: [String]?,
endpointTokens expectedEndpointTokens: [String]? = nil,
httpParameters expectedHTTPParameters: [String]? = nil,
Expand Down