diff --git a/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift b/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift index 939d4ef123..261eba14c7 100644 --- a/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift +++ b/Sources/SwiftDocC/Infrastructure/ConvertActionConverter.swift @@ -147,7 +147,7 @@ package enum ConvertActionConverter { linkSummaries.append(contentsOf: nodeLinkSummaries) indexingRecords.append(contentsOf: nodeIndexingRecords) } - } else if FeatureFlags.current.isExperimentalLinkHierarchySerializationEnabled { + } else if FeatureFlags.current.isLinkHierarchySerializationEnabled { let nodeLinkSummaries = entity.externallyLinkableElementSummaries(context: context, renderNode: renderNode, includeTaskGroups: false) resultsGroup.async(queue: resultsSyncQueue) { @@ -180,7 +180,7 @@ package enum ConvertActionConverter { } } - if FeatureFlags.current.isExperimentalLinkHierarchySerializationEnabled { + if FeatureFlags.current.isLinkHierarchySerializationEnabled { signposter.withIntervalSignpost("Serialize link hierarchy", id: signposter.makeSignpostID()) { do { let serializableLinkInformation = try context.linkResolver.localResolver.prepareForSerialization(bundleID: bundle.id) diff --git a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Find.swift b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Find.swift index b58ec12b27..c8e314ace1 100644 --- a/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Find.swift +++ b/Sources/SwiftDocC/Infrastructure/Link Resolution/PathHierarchy+Find.swift @@ -113,7 +113,7 @@ extension PathHierarchy { } let topLevelNames = Set(modules.map(\.name) + (onlyFindSymbols ? [] : [articlesContainer.name, tutorialContainer.name])) - if isAbsolute, FeatureFlags.current.isExperimentalLinkHierarchySerializationEnabled { + if isAbsolute, FeatureFlags.current.isLinkHierarchySerializationEnabled { throw Error.moduleNotFound( pathPrefix: pathForError(of: rawPath, droppingLast: remaining.count), remaining: Array(remaining), diff --git a/Sources/SwiftDocC/Utility/FeatureFlags.swift b/Sources/SwiftDocC/Utility/FeatureFlags.swift index 8051d44015..1b44a45e78 100644 --- a/Sources/SwiftDocC/Utility/FeatureFlags.swift +++ b/Sources/SwiftDocC/Utility/FeatureFlags.swift @@ -17,8 +17,14 @@ public struct FeatureFlags: Codable { /// Whether or not experimental support for device frames on images and video is enabled. public var isExperimentalDeviceFrameSupportEnabled = false - /// Whether or not experimental support for emitting a serialized version of the local link resolution information is enabled. - public var isExperimentalLinkHierarchySerializationEnabled = false + /// Whether or not support for emitting a serialized version of the local link resolution information is enabled. + public var isLinkHierarchySerializationEnabled = true + + @available(*, deprecated, renamed: "isLinkHierarchySerializationEnabled", message: "Use 'isLinkHierarchySerializationEnabled' instead. This deprecated API will be removed after 6.2 is released") + public var isExperimentalLinkHierarchySerializationEnabled: Bool { + get { isLinkHierarchySerializationEnabled } + set { isLinkHierarchySerializationEnabled = newValue } + } /// Whether or not experimental support for combining overloaded symbol pages is enabled. public var isExperimentalOverloadedSymbolPresentationEnabled = false diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift index 8115032d96..03e9aed502 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/ActionExtensions/ConvertAction+CommandInitialization.swift @@ -21,7 +21,7 @@ extension ConvertAction { let outOfProcessResolver: OutOfProcessReferenceResolver? FeatureFlags.current.isExperimentalDeviceFrameSupportEnabled = convert.enableExperimentalDeviceFrameSupport - FeatureFlags.current.isExperimentalLinkHierarchySerializationEnabled = convert.enableExperimentalLinkHierarchySerialization + FeatureFlags.current.isLinkHierarchySerializationEnabled = convert.enableLinkHierarchySerialization FeatureFlags.current.isExperimentalOverloadedSymbolPresentationEnabled = convert.enableExperimentalOverloadedSymbolPresentation FeatureFlags.current.isExperimentalMentionedInEnabled = convert.enableExperimentalMentionedIn FeatureFlags.current.isParametersAndReturnsValidationEnabled = convert.enableParametersAndReturnsValidation diff --git a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift index fd2cfe99f4..3afd8d9a87 100644 --- a/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift +++ b/Sources/SwiftDocCUtilities/ArgumentParsing/Subcommands/Convert.swift @@ -486,13 +486,19 @@ extension Docc { var allowArbitraryCatalogDirectories = false @Flag( - name: .customLong("enable-experimental-external-link-support"), + name: .customLong("external-link-support"), + inversion: .prefixedEnableDisable, help: ArgumentHelp("Support external links to this documentation output.", discussion: """ Write additional link metadata files to the output directory to support resolving documentation links to the documentation in that output directory. """) ) + var enableLinkHierarchySerialization = true + + // This flag only exist to allow developers to pass the previous '--enable-experimental-...' flag without errors. + @Flag(name: .customLong("enable-experimental-external-link-support"), help: .hidden) + @available(*, deprecated, message: "This deprecated API will be removed after 6.2 is released") var enableExperimentalLinkHierarchySerialization = false - + @Flag(help: .hidden) var experimentalModifyCatalogWithGeneratedCuration = false @@ -536,6 +542,7 @@ extension Docc { Convert.warnAboutDeprecatedOptionIfNeeded("enable-experimental-json-index", message: "This flag has no effect. The JSON render is emitted by default.") Convert.warnAboutDeprecatedOptionIfNeeded("experimental-parse-doxygen-commands", message: "This flag has no effect. Doxygen support is enabled by default.") Convert.warnAboutDeprecatedOptionIfNeeded("enable-experimental-parameters-and-returns-validation", message: "This flag has no effect. Parameter and return value validation is enabled by default.") + Convert.warnAboutDeprecatedOptionIfNeeded("enable-experimental-external-link-support", message: "This flag has no effect. External link support is enabled by default.") Convert.warnAboutDeprecatedOptionIfNeeded("index", message: "Use '--emit-lmdb-index' indead.") emitLMDBIndex = emitLMDBIndex } @@ -575,9 +582,15 @@ extension Docc { } /// A user-provided value that is true if the user enables experimental serialization of the local link resolution information. + public var enableLinkHierarchySerialization: Bool { + get { featureFlags.enableLinkHierarchySerialization } + set { featureFlags.enableLinkHierarchySerialization = newValue } + } + + @available(*, deprecated, renamed: "enableLinkHierarchySerialization", message: "Use 'enableLinkHierarchySerialization' instead. This deprecated API will be removed after 6.2 is released") public var enableExperimentalLinkHierarchySerialization: Bool { - get { featureFlags.enableExperimentalLinkHierarchySerialization } - set { featureFlags.enableExperimentalLinkHierarchySerialization = newValue } + get { enableLinkHierarchySerialization } + set { enableLinkHierarchySerialization = newValue } } /// A user-provided value that is true if the user wants to in-place modify the provided documentation catalog to write generated curation to documentation extension files. diff --git a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift index 0cc3a99385..c51fc88e59 100644 --- a/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/DocumentationContext/DocumentationContextTests.swift @@ -5261,8 +5261,6 @@ let expected = """ } func testResolveExternalLinkFromTechnologyRoot() throws { - enableFeatureFlag(\.isExperimentalLinkHierarchySerializationEnabled) - let externalModuleName = "ExternalModuleName" func makeExternalDependencyFiles() throws -> (SerializableLinkResolutionInformation, [LinkDestinationSummary]) { diff --git a/Tests/SwiftDocCTests/Infrastructure/ExternalPathHierarchyResolverTests.swift b/Tests/SwiftDocCTests/Infrastructure/ExternalPathHierarchyResolverTests.swift index cf55a5d19c..1fe178ccb2 100644 --- a/Tests/SwiftDocCTests/Infrastructure/ExternalPathHierarchyResolverTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/ExternalPathHierarchyResolverTests.swift @@ -16,11 +16,6 @@ import SwiftDocCTestUtilities class ExternalPathHierarchyResolverTests: XCTestCase { - override func setUp() { - super.setUp() - enableFeatureFlag(\.isExperimentalLinkHierarchySerializationEnabled) - } - // These tests resolve absolute symbol links in both a local and external context to verify that external links work the same local links. func testUnambiguousAbsolutePaths() throws { diff --git a/Tests/SwiftDocCTests/Infrastructure/PathHierarchyTests.swift b/Tests/SwiftDocCTests/Infrastructure/PathHierarchyTests.swift index 677e698954..afabb70da8 100644 --- a/Tests/SwiftDocCTests/Infrastructure/PathHierarchyTests.swift +++ b/Tests/SwiftDocCTests/Infrastructure/PathHierarchyTests.swift @@ -287,8 +287,6 @@ class PathHierarchyTests: XCTestCase { } func testAmbiguousPaths() throws { - enableFeatureFlag(\.isExperimentalLinkHierarchySerializationEnabled) - let (_, context) = try testBundleAndContext(named: "MixedLanguageFrameworkWithLanguageRefinements") let tree = context.linkResolver.localResolver.pathHierarchy @@ -3559,8 +3557,6 @@ class PathHierarchyTests: XCTestCase { } func testResolveExternalLinkFromTechnologyRoot() throws { - enableFeatureFlag(\.isExperimentalLinkHierarchySerializationEnabled) - let catalog = Folder(name: "unit-test.docc", content: [ TextFile(name: "Root.md", utf8Content: """ # Some root page diff --git a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift index 4cc94120f2..e4ac406045 100644 --- a/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ArgumentParsing/ConvertSubcommandTests.swift @@ -367,16 +367,16 @@ class ConvertSubcommandTests: XCTestCase { let commandWithoutFlag = try Docc.Convert.parse([testBundleURL.path]) _ = try ConvertAction(fromConvertCommand: commandWithoutFlag) - XCTAssertFalse(commandWithoutFlag.enableExperimentalLinkHierarchySerialization) - XCTAssertFalse(FeatureFlags.current.isExperimentalLinkHierarchySerializationEnabled) + XCTAssertTrue(commandWithoutFlag.enableLinkHierarchySerialization) + XCTAssertTrue(FeatureFlags.current.isLinkHierarchySerializationEnabled) let commandWithFlag = try Docc.Convert.parse([ - "--enable-experimental-external-link-support", + "--disable-external-link-support", testBundleURL.path, ]) _ = try ConvertAction(fromConvertCommand: commandWithFlag) - XCTAssertTrue(commandWithFlag.enableExperimentalLinkHierarchySerialization) - XCTAssertTrue(FeatureFlags.current.isExperimentalLinkHierarchySerializationEnabled) + XCTAssertFalse(commandWithFlag.enableLinkHierarchySerialization) + XCTAssertFalse(FeatureFlags.current.isLinkHierarchySerializationEnabled) } func testExperimentalEnableOverloadedSymbolPresentation() throws { @@ -578,6 +578,24 @@ class ConvertSubcommandTests: XCTestCase { let disabledFlagConvert = try Docc.Convert.parse(["--disable-parameters-and-returns-validation"]) XCTAssertEqual(disabledFlagConvert.enableParametersAndReturnsValidation, false) } + + func testExternalLinkSupportFlag() throws { + // The feature is enabled when no flag is passed. + let noFlagConvert = try Docc.Convert.parse([]) + XCTAssertEqual(noFlagConvert.enableLinkHierarchySerialization, true) + + // It's allowed to pass the previous "--enable-experimental-..." flag. + let oldFlagConvert = try Docc.Convert.parse(["--enable-experimental-external-link-support"]) + XCTAssertEqual(oldFlagConvert.enableLinkHierarchySerialization, true) + + // It's allowed to pass the redundant "--enable-..." flag. + let enabledFlagConvert = try Docc.Convert.parse(["--enable-external-link-support"]) + XCTAssertEqual(enabledFlagConvert.enableLinkHierarchySerialization, true) + + // Passing the "--disable-..." flag turns of the feature. + let disabledFlagConvert = try Docc.Convert.parse(["--disable-external-link-support"]) + XCTAssertEqual(disabledFlagConvert.enableLinkHierarchySerialization, false) + } // This test calls ``ConvertOptions.infoPlistFallbacks._unusedVersionForBackwardsCompatibility`` which is deprecated. // Deprecating the test silences the deprecation warning when running the tests. It doesn't skip the test. diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift index 88c9c1f909..22f5f0179c 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionStaticHostableTests.swift @@ -47,7 +47,11 @@ class ConvertActionStaticHostableTests: StaticHostingBaseTests { _ = try await action.perform(logHandle: .none) // Test the content of the output folder. - var expectedContent = ["data", "documentation", "tutorials", "downloads", "images", "metadata.json" ,"videos", "index.html", "index"] + var expectedContent = [ + "data", "documentation", "tutorials", "downloads", "images", "videos", + "index.html", "index", + "metadata.json", "link-hierarchy.json", "linkable-entities.json" + ] expectedContent += templateFolder.content.filter { $0 is Folder }.map{ $0.name } let output = try fileManager.contentsOfDirectory(atPath: targetBundleURL.path) diff --git a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift index 3adc98c49d..3bcbb01d1b 100644 --- a/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift +++ b/Tests/SwiftDocCUtilitiesTests/ConvertActionTests.swift @@ -1517,7 +1517,6 @@ class ConvertActionTests: XCTestCase { XCTAssertFalse(testDataProvider.fileExists(atPath: result.outputs[0].appendingPathComponent("assets.json").path)) XCTAssertFalse(testDataProvider.fileExists(atPath: result.outputs[0].appendingPathComponent("diagnostics.json").path)) XCTAssertFalse(testDataProvider.fileExists(atPath: result.outputs[0].appendingPathComponent("indexing-records.json").path)) - XCTAssertFalse(testDataProvider.fileExists(atPath: result.outputs[0].appendingPathComponent("linkable-entities.json").path)) } } @@ -3119,6 +3118,8 @@ class ConvertActionTests: XCTestCase { │ ├─ image-name@2x.png │ ├─ image-name~dark.png │ ╰─ image-name~dark@2x.png + ├─ link-hierarchy.json + ├─ linkable-entities.json ├─ metadata.json ╰─ videos/ ╰─ unit-test/