1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2022 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
import Foundation
/// A remote repository that hosts source code.
public struct SourceRepository {
/// The path at which the repository is cloned locally.
public var checkoutPath: String
/// The base URL where the service hosts the repository's contents.
public var sourceServiceBaseURL: URL
/// A function that formats a line number to be included in a URL.
public var formatLineNumber: (Int) -> String
/// Creates a source code repository.
/// - Parameters:
/// - checkoutPath: The path at which the repository is checked out locally and from which its symbol graphs were generated.
/// - sourceServiceBaseURL: The base URL where the service hosts the repository's contents.
/// - formatLineNumber: A function that formats a line number to be included in a URL.
public init(
checkoutPath: String,
sourceServiceBaseURL: URL,
formatLineNumber: @escaping (Int) -> String
) {
self.checkoutPath = checkoutPath
self.sourceServiceBaseURL = sourceServiceBaseURL
self.formatLineNumber = formatLineNumber
}
/// Formats a local source file URL to a URL hosted by the remote source code service.
/// - Parameters:
/// - sourceFileURL: The location of the source file on disk.
/// - lineNumber: A line number in the source file, 1-indexed.
/// - Returns: The URL of the file hosted by the remote source code service if it could be constructed, otherwise, `nil`.
public func format(sourceFileURL: URL, lineNumber: Int? = nil) -> URL? {
guard sourceFileURL.path.hasPrefix(checkoutPath) else {
return nil
}
let path = sourceFileURL.path.dropFirst(checkoutPath.count).removingLeadingSlash
return sourceServiceBaseURL
.appendingPathComponent(path)
.withFragment(lineNumber.map(formatLineNumber))
}
}
public extension SourceRepository {
/// Creates a source repository hosted by the GitHub service.
/// - Parameters:
/// - checkoutPath: The path of the local checkout.
/// - sourceServiceBaseURL: The base URL where the service hosts the repository's contents.
static func github(checkoutPath: String, sourceServiceBaseURL: URL) -> SourceRepository {
SourceRepository(
checkoutPath: checkoutPath,
sourceServiceBaseURL: sourceServiceBaseURL,
formatLineNumber: { line in "L\(line)" }
)
}
/// Creates a source repository hosted by the GitLab service.
/// - Parameters:
/// - checkoutPath: The path of the local checkout.
/// - sourceServiceBaseURL: The base URL where the service hosts the repository's contents.
static func gitlab(checkoutPath: String, sourceServiceBaseURL: URL) -> SourceRepository {
SourceRepository(
checkoutPath: checkoutPath,
sourceServiceBaseURL: sourceServiceBaseURL,
formatLineNumber: { line in "L\(line)" }
)
}
/// Creates a source repository hosted by the BitBucket service.
/// - Parameters:
/// - checkoutPath: The path of the local checkout.
/// - sourceServiceBaseURL: The base URL where the service hosts the repository's contents.
static func bitbucket(checkoutPath: String, sourceServiceBaseURL: URL) -> SourceRepository {
SourceRepository(
checkoutPath: checkoutPath,
sourceServiceBaseURL: sourceServiceBaseURL,
formatLineNumber: { line in "lines-\(line)" }
)
}
/// Creates a source repository hosted by the device's filesystem.
///
/// Use this source repository to format `doc-source-file://` links to files on the
/// device where documentation is being presented.
///
/// This source repository uses a custom scheme to offer more control local source file navigation.
static func localFilesystem() -> SourceRepository {
SourceRepository(
checkoutPath: "",
// 2 slashes to specify an empty authority/host component and 1 slash to specify a base path at the root.
sourceServiceBaseURL: URL(string: "doc-source-file:///")!,
formatLineNumber: { line in "L\(line)" }
)
}
}
|