Skip to content

Commit

Permalink
[SR-15434] Add support for custom (non-framework) module kinds (#33)
Browse files Browse the repository at this point in the history
* Add option to provide a default module kind

Resolves rdar://83448323 and SR-15434.

* Update DocC's user documentation with custom module kind

In this context, DocC is a "Tool" not a "Framework".
  • Loading branch information
ethan-kusters committed Nov 12, 2021
1 parent f1543f0 commit 0752acf
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 1 deletion.
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>

0 comments on commit 0752acf

Please sign in to comment.