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

[SR-15434] Add support for custom (non-framework) module kinds #33

Merged
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
2 changes: 2 additions & 0 deletions Sources/DocCDocumentation/DocCDocumentation.docc/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,7 @@
<string>0.1.0</string>
<key>CFBundleVersion</key>
<string>0.1.0</string>
<key>CDDefaultModuleKind</key>
<string>Tool</string>
</dict>
</plist>
6 changes: 5 additions & 1 deletion Sources/SwiftDocC/Infrastructure/DocumentationContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1096,13 +1096,17 @@ public class DocumentationContext: DocumentationContextDataProviderDelegate {

// Create a module symbol
let moduleIdentifier = SymbolGraph.Symbol.Identifier(precise: moduleName, interfaceLanguage: SourceLanguage.swift.id)

// Use the default module kind for this bundle if one was provided,
// otherwise fall back to 'Framework'
let moduleKindDisplayName = bundle.info.defaultModuleKind ?? "Framework"
let moduleSymbol = SymbolGraph.Symbol(
identifier: moduleIdentifier,
names: SymbolGraph.Symbol.Names(title: moduleName, navigator: nil, subHeading: nil, prose: nil),
pathComponents: [moduleName],
docComment: nil,
accessLevel: SymbolGraph.Symbol.AccessControl(rawValue: "public"),
kind: SymbolGraph.Symbol.Kind(parsedIdentifier: .module, displayName: "Framework"),
kind: SymbolGraph.Symbol.Kind(parsedIdentifier: .module, displayName: moduleKindDisplayName),
mixins: [:])
let moduleSymbolReference = SymbolReference(moduleName, interfaceLanguage: .swift, symbol: moduleSymbol)
moduleReference = ResolvedTopicReference(symbolReference: moduleSymbolReference, moduleName: moduleName, bundle: bundle)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ extension DocumentationBundle {
/// The default availability for the various modules in the bundle.
public var defaultAvailability: DefaultAvailability?

/// The default kind for the various modules in the bundle.
public var defaultModuleKind: String?

/// The keys that must be present in an Info.plist file in order for doc compilation to proceed.
static let requiredKeys: Set<CodingKeys> = [.displayName, .identifier, .version]

Expand All @@ -39,6 +42,7 @@ extension DocumentationBundle {
case version = "CFBundleVersion"
case defaultCodeListingLanguage = "CDDefaultCodeListingLanguage"
case defaultAvailability = "CDAppleDefaultAvailability"
case defaultModuleKind = "CDDefaultModuleKind"

var argumentName: String? {
switch self {
Expand All @@ -50,6 +54,8 @@ extension DocumentationBundle {
return "--fallback-bundle-version"
case .defaultCodeListingLanguage:
return "--default-code-listing-language"
case .defaultModuleKind:
return "--fallback-default-module-kind"
case .defaultAvailability:
return nil
}
Expand Down Expand Up @@ -161,6 +167,7 @@ extension DocumentationBundle {
// Finally, decode the optional keys if they're present.

self.defaultCodeListingLanguage = try decodeOrFallbackIfPresent(String.self, with: .defaultCodeListingLanguage)
self.defaultModuleKind = try decodeOrFallbackIfPresent(String.self, with: .defaultModuleKind)
self.defaultAvailability = try decodeOrFallbackIfPresent(DefaultAvailability.self, with: .defaultAvailability)
}

Expand All @@ -169,12 +176,14 @@ extension DocumentationBundle {
identifier: String,
version: Version,
defaultCodeListingLanguage: String? = nil,
defaultModuleKind: String? = nil,
defaultAvailability: DefaultAvailability? = nil
) {
self.displayName = displayName
self.identifier = identifier
self.version = version
self.defaultCodeListingLanguage = defaultCodeListingLanguage
self.defaultModuleKind = defaultModuleKind
self.defaultAvailability = defaultAvailability
}
}
Expand All @@ -198,6 +207,7 @@ extension BundleDiscoveryOptions {
fallbackIdentifier: String? = nil,
fallbackVersion: String? = nil,
fallbackDefaultCodeListingLanguage: String? = nil,
fallbackDefaultModuleKind: String? = nil,
fallbackDefaultAvailability: DefaultAvailability? = nil,
additionalSymbolGraphFiles: [URL] = []
) {
Expand All @@ -220,6 +230,8 @@ extension BundleDiscoveryOptions {
value = fallbackDefaultCodeListingLanguage
case .defaultAvailability:
value = fallbackDefaultAvailability
case .defaultModuleKind:
value = fallbackDefaultModuleKind
}

guard let unwrappedValue = value else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ extension ConvertAction {
fallbackIdentifier: convert.fallbackBundleIdentifier,
fallbackVersion: convert.fallbackBundleVersion,
fallbackDefaultCodeListingLanguage: convert.defaultCodeListingLanguage,
fallbackDefaultModuleKind: convert.fallbackDefaultModuleKind,
additionalSymbolGraphFiles: additionalSymbolGraphFiles
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ extension Docc {
help: "A fallback default language for code listings if no value is provided in the documentation bundle's Info.plist file."
)
public var defaultCodeListingLanguage: String?

@Option(
help: """
A fallback default module kind if no value is provided \
in the documentation bundle's Info.plist file.
"""
)
public var fallbackDefaultModuleKind: String?

/// A user-provided location where the convert action writes the built documentation.
@Option(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ class DocumentationBundleInfoTests: XCTestCase {
</dict>
<key>CDDefaultCodeListingLanguage</key>
<string>swift</string>
<key>CDDefaultModuleKind</key>
<string>Executable</string>
<key>CFBundleDisplayName</key>
<string>ShapeKit</string>
<key>CFBundleIdentifier</key>
Expand Down Expand Up @@ -196,6 +198,7 @@ class DocumentationBundleInfoTests: XCTestCase {
fallbackIdentifier: "swift.org.Identifier",
fallbackVersion: "1.0.0",
fallbackDefaultCodeListingLanguage: "swift",
fallbackDefaultModuleKind: "Executable",
fallbackDefaultAvailability: DefaultAvailability(
with: [
"MyModule": [
Expand All @@ -216,6 +219,7 @@ class DocumentationBundleInfoTests: XCTestCase {
identifier: "swift.org.Identifier",
version: Version(arrayLiteral: 1,0,0),
defaultCodeListingLanguage: "swift",
defaultModuleKind: "Executable",
defaultAvailability: DefaultAvailability(
with: [
"MyModule": [
Expand All @@ -236,6 +240,7 @@ class DocumentationBundleInfoTests: XCTestCase {
identifier: "swift.org.Identifier",
version: Version(arrayLiteral: 1,0,0),
defaultCodeListingLanguage: "swift",
defaultModuleKind: "Executable",
defaultAvailability: DefaultAvailability(
with: [
"MyModule": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2972,6 +2972,15 @@ let expected = """
// Verify the solution proposes the expected absolute link replacement.
XCTAssertEqual(problem.possibleSolutions[0].replacements[0].replacement, "<doc:/documentation/Minimal_docs/A/method(_:)-7mctk>")
}

func testCustomModuleKind() throws {
let (bundle, context) = try testBundleAndContext(named: "BundleWithExecutableModuleKind")
XCTAssertEqual(bundle.info.defaultModuleKind, "Executable")

let moduleSymbol = try XCTUnwrap(context.symbolIndex["ExampleDocumentedExecutable"]?.symbol)
XCTAssertEqual(moduleSymbol.kind.identifier.identifier, "module")
XCTAssertEqual(moduleSymbol.kind.displayName, "Executable")
}
}

func assertEqualDumps(_ lhs: String, _ rhs: String, file: StaticString = #file, line: UInt = #line) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
{
"metadata": {
"formatVersion": {
"major": 0,
"minor": 5,
"patch": 3
},
"generator": "Apple Swift version 5.5 (swiftlang-1300.0.29.1 clang-1300.0.28.1)"
},
"module": {
"name": "ExampleDocumentedExecutable",
"platform": {
"architecture": "arm64",
"vendor": "apple",
"operatingSystem": {
"name": "macosx",
"minimumVersion": {
"major": 10,
"minor": 10,
"patch": 0
}
}
}
},
"symbols": [
{
"kind": {
"identifier": "swift.struct",
"displayName": "Structure"
},
"identifier": {
"precise": "s:27ExampleDocumentedExecutableAAV",
"interfaceLanguage": "swift"
},
"pathComponents": [
"ExampleDocumentedExecutable"
],
"names": {
"title": "ExampleDocumentedExecutable",
"navigator": [
{
"kind": "identifier",
"spelling": "ExampleDocumentedExecutable"
}
],
"subHeading": [
{
"kind": "keyword",
"spelling": "struct"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "ExampleDocumentedExecutable"
}
]
},
"docComment": {
"lines": [
{
"range": {
"start": {
"line": 0,
"character": 4
},
"end": {
"line": 0,
"character": 55
}
},
"text": "This is a description of what this executable does."
}
]
},
"declarationFragments": [
{
"kind": "attribute",
"spelling": "@main"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "keyword",
"spelling": "struct"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "ExampleDocumentedExecutable"
}
],
"accessLevel": "internal",
"location": {
"uri": "file:///Users/demo/Downloads/ExampleDocumentedExecutable/Sources/ExampleDocumentedExecutable/ExampleDocumentedExecutable.swift",
"position": {
"line": 2,
"character": 14
}
}
},
{
"kind": {
"identifier": "swift.type.method",
"displayName": "Type Method"
},
"identifier": {
"precise": "s:27ExampleDocumentedExecutableAAV4mainyyFZ",
"interfaceLanguage": "swift"
},
"pathComponents": [
"ExampleDocumentedExecutable",
"main()"
],
"names": {
"title": "main()",
"subHeading": [
{
"kind": "keyword",
"spelling": "static"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "keyword",
"spelling": "func"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "main"
},
{
"kind": "text",
"spelling": "()"
}
]
},
"functionSignature": {
"returns": [
{
"kind": "text",
"spelling": "()"
}
]
},
"declarationFragments": [
{
"kind": "keyword",
"spelling": "static"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "keyword",
"spelling": "func"
},
{
"kind": "text",
"spelling": " "
},
{
"kind": "identifier",
"spelling": "main"
},
{
"kind": "text",
"spelling": "()"
}
],
"accessLevel": "internal",
"location": {
"uri": "file:///Users/username/Downloads/ExampleDocumentedExecutable/Sources/ExampleDocumentedExecutable/ExampleDocumentedExecutable.swift",
"position": {
"line": 3,
"character": 23
}
}
}
],
"relationships": [
{
"kind": "memberOf",
"source": "s:27ExampleDocumentedExecutableAAV4mainyyFZ",
"target": "s:27ExampleDocumentedExecutableAAV"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>ExampleDocumentedExecutable</string>
<key>CFBundleDisplayName</key>
<string>My Executable</string>
<key>CFBundleIdentifier</key>
<string>org.swift.Executable</string>
<key>CFBundleVersion</key>
<string>0.1.0</string>
<key>CDDefaultModuleKind</key>
<string>Executable</string>
</dict>
</plist>