Skip to content

Commit 887308b

Browse files
authored
Document the default behavior of the DocumentationExtension directive (#833)
* Document DocumentationExtension directive's default behavior rdar://79096832 * Raise a warning for redundant DocumentationExtension configuration * Increase severity to 'warning' so that its emitted by default * Fix test that was asserting "append" behavior
1 parent d06f82c commit 887308b

File tree

7 files changed

+71
-76
lines changed

7 files changed

+71
-76
lines changed

Sources/SwiftDocC/Semantics/Metadata/DocumentationExtension.swift

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2021-2023 Apple Inc. and the Swift project authors
4+
Copyright (c) 2021-2024 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -11,26 +11,28 @@
1111
import Foundation
1212
import Markdown
1313

14-
/// A directive that controls how the documentation-extension file merges with or overrides the in-source documentation.
14+
/// Defines whether the content in a documentation extension file amends or replaces in-source documentation.
1515
///
16-
/// When the ``behavior`` property is ``Behavior/append``, the content from the documentation-extension file is added after the content from
17-
/// the in-source documentation for that symbol.
18-
/// If a documentation-extension file doesn't have a `DocumentationExtension` directive, then it has the ``Behavior/append`` behavior.
16+
/// By default, content from the documentation-extension file is added after the content from the in-source documentation for that symbol.
1917
///
20-
/// When the ``behavior`` property is ``Behavior/override``, the content from the documentation-extension file completely replaces the content
21-
/// from the in-source documentation for that symbol
18+
/// You get this default behavior in two cases:
19+
/// - when the documentation-extension file doesn't have a `DocumentationExtension` directive
20+
/// - when the `DocumentationExtension` directive explicitly specifies the ``Behavior/append`` behavior
21+
///
22+
/// The other merge behavior completely replaces the content from the in-source documentation for that symbol with the content from the documentation-extension file. To get this behavior, specify ``Behavior/override`` as the merge behavior.
2223
///
23-
/// This directive is only valid within a ``Metadata`` directive:
2424
/// ```
2525
/// @Metadata {
2626
/// @DocumentationExtension(mergeBehavior: override)
2727
/// }
2828
/// ```
29+
///
30+
/// The `DocumentationExtension` is only valid within a ``Metadata`` directive.
2931
public final class DocumentationExtension: Semantic, AutomaticDirectiveConvertible {
3032
public static let introducedVersion = "5.5"
3133
public let originalMarkup: BlockDirective
3234

33-
/// The merge behavior for this documentation extension.
35+
/// A value of `append` or `override`, denoting whether an extension file's content amends or replaces the in-source documentation.
3436
@DirectiveArgumentWrapped(name: .custom("mergeBehavior"))
3537
public var behavior: Behavior
3638

@@ -47,6 +49,25 @@ public final class DocumentationExtension: Semantic, AutomaticDirectiveConvertib
4749
case override
4850
}
4951

52+
func validate(source: URL?, for bundle: DocumentationBundle, in context: DocumentationContext, problems: inout [Problem]) -> Bool {
53+
if behavior == .append {
54+
let diagnostic = Diagnostic(
55+
source: source,
56+
severity: .warning,
57+
range: originalMarkup.range,
58+
identifier: "org.swift.docc.\(Self.directiveName).NoConfiguration",
59+
summary: "\(Self.directiveName.singleQuoted) doesn't change default configuration and has no effect"
60+
)
61+
62+
let solutions = originalMarkup.range.map {
63+
[Solution(summary: "Remove this \(Self.directiveName.singleQuoted) directive.", replacements: [Replacement(range: $0, replacement: "")])]
64+
} ?? []
65+
problems.append(Problem(diagnostic: diagnostic, possibleSolutions: solutions))
66+
}
67+
68+
return true
69+
}
70+
5071
@available(*, deprecated, message: "Do not call directly. Required for 'AutomaticDirectiveConvertible'.")
5172
init(originalMarkup: BlockDirective) {
5273
self.originalMarkup = originalMarkup
Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
1-
# ``docc/DocumentationExtension``
1+
# ``DocumentationExtension``
22

3-
Defines whether the content in a documentation extension file amends or replaces in-source documentation.
3+
Defines whether the content in a documentation extension file replaces in-source documentation or amends it (the default).
44

55
@Metadata {
66
@DocumentationExtension(mergeBehavior: override)
77
}
88

99
- Parameters:
10-
- mergeBehavior: A value of `append` or `override`, denoting whether an extension file's content amends or replaces the in-source documentation. **(required)**
10+
- mergeBehavior: A value of `override` to replace the in-source documentation with the extension file's content. **(required)**
1111

1212
## Overview
1313

14+
By default, content from the documentation-extension file is added after the content from the in-source documentation for that symbol.
15+
1416
Swift framework and package APIs are typically documented using comments that reside in-source, alongside the APIs themselves. In some cases, you may wish to supplement or replace in-source documentation with content from dedicated documentation extension files. To learn about this process, see <doc:adding-supplemental-content-to-a-documentation-catalog>.
1517

1618
Place the `DocumentationExtension` directive within a `Metadata` directive in a documentation extension file. Set the `mergeBehavior` parameter to `append` or `override` to indicate whether the extension file's content amends or replaces the in-source documentation.
1719

1820
```
19-
# ``SlothCreator/Sloth``
20-
2121
@Metadata {
22-
@DocumentationExtension(mergeBehavior: append)
22+
@DocumentationExtension(mergeBehavior: override)
2323
}
24+
```
2425

25-
## Sleeping Habits
26-
27-
Sloths sleep in trees by curling into a ball and hanging by their claws.
28-
````
26+
> Note:
27+
> You can specify a `append` merge behavior but it has the same effect as not defining a `@DocumentationExtension` and results in a warning.
2928
3029
### Containing Elements
3130

3231
The following items can include a documentation extension element:
3332

3433
- ``Metadata``
3534

36-
<!-- Copyright (c) 2021 Apple Inc and the Swift Project authors. All Rights Reserved. -->
35+
<!-- Copyright (c) 2021-2024 Apple Inc and the Swift Project authors. All Rights Reserved. -->

Sources/docc/DocCDocumentation.docc/Reference Syntax/API Reference Syntax/Metadata.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ Use metadata directives to instruct DocC how to build certain documentation file
88

99
## Overview
1010

11-
Use the `Metadata` directive with other directives to configure how certain documentation files build. Place the directive after the documentation page's title. Use it with the ``DocumentationExtension`` directive to indicate whether content in a documentation extension file amends or replaces in-source documentation.
11+
Use the `Metadata` directive with other directives to configure how certain documentation files build. Place the directive after the documentation page's title.
12+
13+
Use it with the ``DocumentationExtension`` directive to replace in-source documentation with the documentation extension file's content.
1214

1315
```
1416
# ``SlothCreator/Sloth``
1517
1618
@Metadata {
17-
@DocumentationExtension(mergeBehavior: append)
19+
@DocumentationExtension(mergeBehavior: override)
1820
}
19-
````
21+
```
2022

2123
Use the `Metadata` directive with the ``TechnologyRoot`` directive to configure a documentation page that's not associated with a particular framework, so that page appears as a top-level page.
2224

@@ -88,4 +90,4 @@ previous versions, @Redirected must be used as a top level directive.
8890
> Note: Starting with version 5.11, @Redirected is supported as a child directive of @Metadata. In
8991
previous versions, @Redirected must be used as a top level directive.
9092

91-
<!-- Copyright (c) 2021-2023 Apple Inc and the Swift Project authors. All Rights Reserved. -->
93+
<!-- Copyright (c) 2021-2024 Apple Inc and the Swift Project authors. All Rights Reserved. -->

Sources/docc/DocCDocumentation.docc/adding-supplemental-content-to-a-documentation-catalog.md

Lines changed: 15 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Create a sloth and assign personality traits and abilities.
6060
Sloths are complex creatures that require careful creation and a suitable
6161
habitat.
6262
...
63-
````
63+
```
6464

6565
To add an article to your documentation catalog, use a text editor and create a file with an appropriate title and add a `.md` extension.
6666

@@ -82,62 +82,35 @@ about organizing your project's documentation, see
8282

8383
### Add Extension Files to Append to or Override Source Documentation Comments
8484

85-
Although writing documentation comments in source files has many benefits, in some
86-
circumstances it makes more sense to separate the content from the source
87-
files, such as:
85+
Although writing documentation comments in source files has many benefits, in some circumstances it makes more sense to separate content from the source files, such as:
8886

8987
* When you include thorough code listings or numerous images that increase the
9088
size of your documentation and make source files difficult to manage
9189
* When your source documentation comments focus on the implementation of your
9290
code, and aren't appropriate for external documentation
9391

94-
In cases like these, DocC supports supplementing or completely replacing source
95-
documentation comments with content in extension files. To add an extension file to your
96-
documentation catalog, create a file within the documentation catalog, then modify the first line of the file to identify the symbol that the file relates to.
92+
To add an extension file to your documentation catalog, create a file within the documentation catalog, then modify the first line of the file to identify the symbol that the file relates to using a symbol link in a level 1 header.
93+
For more information on linking to symbols, see <doc:linking-to-symbols-and-other-content>.
9794

98-
> Important: The symbol path for the page title of an extension file need to start
99-
with the name of a top-level symbol or the name of the framework.
95+
> Important: The symbol path for the page title of an extension file need to start with the name of a top-level symbol or the name of the framework.
10096
101-
If the symbol already has source documentation comments, add a
102-
`DocumentationExtension` directive to specify whether the content of the
103-
extension file appends to or overrides the source documentation comments. Add
104-
the `DocumentationExtension` after the first line of the file that specifies
105-
the symbol, using the following format:
106-
107-
````markdown
108-
@Metadata {
109-
@DocumentationExtension(mergeBehavior: [append or override])
110-
}
111-
````
112-
113-
The `mergeBehavior` parameter determines whether DocC adds the extension file's
114-
content to the bottom of the source documentation comments, or replaces
115-
the source documentation comments entirely.
116-
117-
To add the extension file's content to source documentation comments, use
118-
`append` for the `mergeBehavior`. For example, to add a section
119-
about the sleeping habits of sloths to the `Sloth` type, the extension file
120-
contains the following:
97+
By default, the extension file's content adds to the symbol's existing source documentation comment.
98+
You can leave key information in the documentation comment---where it's available to people reading the source code---and use the extension file for longer documentation, code examples, images, and for organizing you documentation hierarchy.
99+
For example, to add a section about the sleeping habits of sloths to the `Sloth` type, the extension file contains the following:
121100

122101
```markdown
123-
# ``SlothCreator/Sloth``
124-
125-
@Metadata {
126-
@DocumentationExtension(mergeBehavior: append)
127-
}
102+
# ``Sloth``
128103

129104
## Sleeping Habits
130105

131106
Sloths sleep in trees by curling into a ball and hanging by their claws.
132-
````
107+
```
133108

134-
Alternatively, to completely replace the source documentation comments, use
135-
`override`. In this case, you add content after the directive that DocC uses
136-
when generating documentation. For example, to replace the source documentation
137-
comments of the `Sloth` type in SlothCreator, the extension file contains the following:
109+
If the symbol's existing source documentation focuses on implementation and isn't appropriate for external documentation, you can completely replace the documentation comment's content with the extension file's content by adding a ``DocumentationExtension`` directive.
110+
For example, to replace the source documentation comments of the `Sloth` type in SlothCreator, the extension file contains the following:
138111

139112
```markdown
140-
# ``SlothCreator/Sloth``
113+
# ``Sloth``
141114

142115
@Metadata {
143116
@DocumentationExtension(mergeBehavior: override)
@@ -148,9 +121,9 @@ This overrides the in-source summary.
148121
## Overview
149122

150123
This content overrides in-source content.
151-
````
124+
```
152125

153126
For more information on `Metadata` and other directives, see
154127
<doc:Metadata>.
155128

156-
<!-- Copyright (c) 2021-2023 Apple Inc and the Swift Project authors. All Rights Reserved. -->
129+
<!-- Copyright (c) 2021-2024 Apple Inc and the Swift Project authors. All Rights Reserved. -->

Tests/SwiftDocCTests/Semantics/DocumentationExtensionTests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ class DocumentationExtensionTests: XCTestCase {
3636
var problems = [Problem]()
3737
let options = DocumentationExtension(from: directive, source: nil, for: bundle, in: context, problems: &problems)
3838
XCTAssertNotNil(options)
39-
XCTAssertTrue(problems.isEmpty)
39+
XCTAssertEqual(problems.count, 1)
40+
XCTAssertEqual("org.swift.docc.DocumentationExtension.NoConfiguration", problems.first?.diagnostic.identifier)
4041
XCTAssertEqual(options?.behavior, .append)
4142
}
4243

@@ -66,7 +67,7 @@ class DocumentationExtensionTests: XCTestCase {
6667
}
6768

6869
func testExtraArguments() throws {
69-
let source = "@DocumentationExtension(mergeBehavior: append, argument: value)"
70+
let source = "@DocumentationExtension(mergeBehavior: override, argument: value)"
7071
let document = Document(parsing: source, options: .parseBlockDirectives)
7172
let directive = document.child(at: 0)! as! BlockDirective
7273
let (bundle, context) = try testBundleAndContext(named: "TestBundle")

Tests/SwiftDocCTests/Semantics/MetadataTests.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class MetadataTests: XCTestCase {
8383
func testDocumentationExtensionSupport() throws {
8484
let source = """
8585
@Metadata {
86-
@DocumentationExtension(mergeBehavior: append)
86+
@DocumentationExtension(mergeBehavior: override)
8787
}
8888
"""
8989
let document = Document(parsing: source, options: .parseBlockDirectives)
@@ -93,7 +93,7 @@ class MetadataTests: XCTestCase {
9393
let metadata = Metadata(from: directive, source: nil, for: bundle, in: context, problems: &problems)
9494
XCTAssertNotNil(metadata)
9595
XCTAssertEqual(0, problems.count)
96-
XCTAssertEqual(metadata?.documentationOptions?.behavior, .append)
96+
XCTAssertEqual(metadata?.documentationOptions?.behavior, .override)
9797
}
9898

9999
func testRepeatDocumentationExtension() throws {
@@ -109,8 +109,11 @@ class MetadataTests: XCTestCase {
109109
var problems = [Problem]()
110110
let metadata = Metadata(from: directive, source: nil, for: bundle, in: context, problems: &problems)
111111
XCTAssertNotNil(metadata)
112-
XCTAssertEqual(1, problems.count)
113-
XCTAssertEqual("org.swift.docc.HasAtMostOne<Metadata, DocumentationExtension>.DuplicateChildren", problems.first?.diagnostic.identifier)
112+
XCTAssertEqual(2, problems.count)
113+
XCTAssertEqual(problems.map(\.diagnostic.identifier).sorted(), [
114+
"org.swift.docc.DocumentationExtension.NoConfiguration",
115+
"org.swift.docc.HasAtMostOne<Metadata, DocumentationExtension>.DuplicateChildren",
116+
])
114117
XCTAssertEqual(metadata?.documentationOptions?.behavior, .append)
115118
}
116119

Tests/SwiftDocCTests/Semantics/SymbolTests.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,6 @@ class SymbolTests: XCTestCase {
150150
""",
151151
articleContent: """
152152
# Leading heading is ignored
153-
154-
@Metadata {
155-
@DocumentationExtension(mergeBehavior: append)
156-
}
157153
"""
158154
)
159155
XCTAssert(problems.isEmpty)

0 commit comments

Comments
 (0)