diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a075d322..5fedde373 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Sourcery CHANGELOG +## Main +## New Features +- Adds `xcframework` key to `target` object in configuration file to enable processing of `swiftinterface` + ## 1.7.0 ## New Features diff --git a/Sourcery/Configuration.swift b/Sourcery/Configuration.swift index c09325ec3..3c7e7752d 100644 --- a/Sourcery/Configuration.swift +++ b/Sourcery/Configuration.swift @@ -12,15 +12,55 @@ public struct Project { public let exclude: [Path] public struct Target { + + public struct XCFramework { + + public let path: Path + public let swiftInterfacePath: Path + + public init(rawPath: String, relativePath: Path) throws { + let frameworkRelativePath = Path(rawPath, relativeTo: relativePath) + guard let framework = frameworkRelativePath.components.last else { + throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected String.") + } + let `extension` = Path(framework).`extension` + guard `extension` == "xcframework" else { + throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected path to xcframework file.") + } + let moduleName = Path(framework).lastComponentWithoutExtension + guard + let simulatorSlicePath = frameworkRelativePath.glob("*") + .first(where: { $0.lastComponent.contains("simulator") }) + else { + throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected to find simulator slice.") + } + let modulePath = simulatorSlicePath + Path("\(moduleName).framework/Modules/\(moduleName).swiftmodule/") + guard let interfacePath = modulePath.glob("*.swiftinterface").first(where: { $0.lastComponent.contains("simulator") }) + else { + throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected to find .swiftinterface.") + } + self.path = frameworkRelativePath + self.swiftInterfacePath = interfacePath + } + } + public let name: String public let module: String + public let xcframeworks: [XCFramework] - public init(dict: [String: String]) throws { - guard let name = dict["name"] else { + public init(dict: [String: Any], relativePath: Path) throws { + guard let name = dict["name"] as? String else { throw Configuration.Error.invalidSources(message: "Target name is not provided. Expected string.") } self.name = name - self.module = dict["module"] ?? name + self.module = (dict["module"] as? String) ?? name + do { + self.xcframeworks = try (dict["xcframeworks"] as? [String])? + .map { try XCFramework(rawPath: $0, relativePath: relativePath) } ?? [] + } catch let error as Configuration.Error { + Log.warning(error.description) + self.xcframeworks = [] + } } } @@ -30,10 +70,10 @@ public struct Project { } let targetsArray: [Target] - if let targets = dict["target"] as? [[String: String]] { - targetsArray = try targets.map({ try Target(dict: $0) }) - } else if let target = dict["target"] as? [String: String] { - targetsArray = try [Target(dict: target)] + if let targets = dict["target"] as? [[String: Any]] { + targetsArray = try targets.map({ try Target(dict: $0, relativePath: relativePath) }) + } else if let target = dict["target"] as? [String: Any] { + targetsArray = try [Target(dict: target, relativePath: relativePath)] } else { throw Configuration.Error.invalidSources(message: "'target' key is missing. Expected object or array of objects.") } @@ -209,6 +249,7 @@ public struct Configuration { public enum Error: Swift.Error, CustomStringConvertible { case invalidFormat(message: String) case invalidSources(message: String) + case invalidXCFramework(message: String) case invalidTemplates(message: String) case invalidOutput(message: String) case invalidCacheBasePath(message: String) @@ -220,6 +261,8 @@ public struct Configuration { return "Invalid config file format. \(message)" case .invalidSources(let message): return "Invalid sources. \(message)" + case .invalidXCFramework(let message): + return "Invalid xcframework. \(message)" case .invalidTemplates(let message): return "Invalid templates. \(message)" case .invalidOutput(let message): diff --git a/Sourcery/Sourcery.swift b/Sourcery/Sourcery.swift index 844e1ccc4..de5331b32 100644 --- a/Sourcery/Sourcery.swift +++ b/Sourcery/Sourcery.swift @@ -95,6 +95,10 @@ public class Sourcery { paths.append(file) modules.append(target.module) } + for framework in target.xcframeworks { + paths.append(framework.swiftInterfacePath) + modules.append(target.module) + } } } result = try self.parse(from: paths, forceParse: forceParse, parseDocumentation: parseDocumentation, modules: modules, requiresFileParserCopy: hasSwiftTemplates) diff --git a/SourceryUtils/Sources/Path+Extensions.swift b/SourceryUtils/Sources/Path+Extensions.swift index ca3c9c661..48f22cf59 100644 --- a/SourceryUtils/Sources/Path+Extensions.swift +++ b/SourceryUtils/Sources/Path+Extensions.swift @@ -52,7 +52,7 @@ extension Path { } public var isSwiftSourceFile: Bool { - return !self.isDirectory && self.extension == "swift" + return !self.isDirectory && (self.extension == "swift" || self.extension == "swiftinterface") } public func hasExtension(as string: String) -> Bool { diff --git a/docs/usage.html b/docs/usage.html index 7595d182f..8bcabc2e6 100644 --- a/docs/usage.html +++ b/docs/usage.html @@ -293,12 +293,15 @@

Sources

- <source file path> -

Or you can provide project which will be scanned and which source files will be processed. You can use several project or target objects to scan multiple targets from one project or to scan multiple projects.

+

Or you can provide project which will be scanned and which source files will be processed. You can use several project or target objects to scan multiple targets from one project or to scan multiple projects. You can provide paths to XCFramework files if your target has any and you want to process their swiftinterface files.

project:
   file: <path to xcodeproj file>
   target:
     name: <target name>
     module: <module name> //required if different from target name
+    xcframeworks:
+    - <path to xcframework file>
+    - <path to xcframework file>
 

Excluding sources or templates

diff --git a/guides/Usage.md b/guides/Usage.md index 25e02f452..66e01ad7c 100644 --- a/guides/Usage.md +++ b/guides/Usage.md @@ -87,7 +87,7 @@ sources: - ``` -Or you can provide project which will be scanned and which source files will be processed. You can use several `project` or `target` objects to scan multiple targets from one project or to scan multiple projects. +Or you can provide project which will be scanned and which source files will be processed. You can use several `project` or `target` objects to scan multiple targets from one project or to scan multiple projects. You can provide paths to XCFramework files if your target has any and you want to process their `swiftinterface` files. ```yaml project: @@ -95,6 +95,9 @@ project: target: name: module: //required if different from target name + xcframeworks: + - + - ``` #### Excluding sources or templates