Skip to content

Commit 75e91b5

Browse files
authored
Parsing .swiftinterface form xcframework (#1035)
* Parsing swift interface * Naming * Supporting array for xcframework key * Documentation Co-authored-by: i.myakotin <>
1 parent 75b1b26 commit 75e91b5

File tree

6 files changed

+67
-10
lines changed

6 files changed

+67
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Sourcery CHANGELOG
22

3+
## Main
4+
## New Features
5+
- Adds `xcframework` key to `target` object in configuration file to enable processing of `swiftinterface`
6+
37
## 1.7.0
48

59
## New Features

Sourcery/Configuration.swift

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,55 @@ public struct Project {
1212
public let exclude: [Path]
1313

1414
public struct Target {
15+
16+
public struct XCFramework {
17+
18+
public let path: Path
19+
public let swiftInterfacePath: Path
20+
21+
public init(rawPath: String, relativePath: Path) throws {
22+
let frameworkRelativePath = Path(rawPath, relativeTo: relativePath)
23+
guard let framework = frameworkRelativePath.components.last else {
24+
throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected String.")
25+
}
26+
let `extension` = Path(framework).`extension`
27+
guard `extension` == "xcframework" else {
28+
throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected path to xcframework file.")
29+
}
30+
let moduleName = Path(framework).lastComponentWithoutExtension
31+
guard
32+
let simulatorSlicePath = frameworkRelativePath.glob("*")
33+
.first(where: { $0.lastComponent.contains("simulator") })
34+
else {
35+
throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected to find simulator slice.")
36+
}
37+
let modulePath = simulatorSlicePath + Path("\(moduleName).framework/Modules/\(moduleName).swiftmodule/")
38+
guard let interfacePath = modulePath.glob("*.swiftinterface").first(where: { $0.lastComponent.contains("simulator") })
39+
else {
40+
throw Configuration.Error.invalidXCFramework(message: "Framework path invalid. Expected to find .swiftinterface.")
41+
}
42+
self.path = frameworkRelativePath
43+
self.swiftInterfacePath = interfacePath
44+
}
45+
}
46+
1547
public let name: String
1648
public let module: String
49+
public let xcframeworks: [XCFramework]
1750

18-
public init(dict: [String: String]) throws {
19-
guard let name = dict["name"] else {
51+
public init(dict: [String: Any], relativePath: Path) throws {
52+
guard let name = dict["name"] as? String else {
2053
throw Configuration.Error.invalidSources(message: "Target name is not provided. Expected string.")
2154
}
2255
self.name = name
23-
self.module = dict["module"] ?? name
56+
self.module = (dict["module"] as? String) ?? name
57+
do {
58+
self.xcframeworks = try (dict["xcframeworks"] as? [String])?
59+
.map { try XCFramework(rawPath: $0, relativePath: relativePath) } ?? []
60+
} catch let error as Configuration.Error {
61+
Log.warning(error.description)
62+
self.xcframeworks = []
63+
}
2464
}
2565
}
2666

@@ -30,10 +70,10 @@ public struct Project {
3070
}
3171

3272
let targetsArray: [Target]
33-
if let targets = dict["target"] as? [[String: String]] {
34-
targetsArray = try targets.map({ try Target(dict: $0) })
35-
} else if let target = dict["target"] as? [String: String] {
36-
targetsArray = try [Target(dict: target)]
73+
if let targets = dict["target"] as? [[String: Any]] {
74+
targetsArray = try targets.map({ try Target(dict: $0, relativePath: relativePath) })
75+
} else if let target = dict["target"] as? [String: Any] {
76+
targetsArray = try [Target(dict: target, relativePath: relativePath)]
3777
} else {
3878
throw Configuration.Error.invalidSources(message: "'target' key is missing. Expected object or array of objects.")
3979
}
@@ -209,6 +249,7 @@ public struct Configuration {
209249
public enum Error: Swift.Error, CustomStringConvertible {
210250
case invalidFormat(message: String)
211251
case invalidSources(message: String)
252+
case invalidXCFramework(message: String)
212253
case invalidTemplates(message: String)
213254
case invalidOutput(message: String)
214255
case invalidCacheBasePath(message: String)
@@ -220,6 +261,8 @@ public struct Configuration {
220261
return "Invalid config file format. \(message)"
221262
case .invalidSources(let message):
222263
return "Invalid sources. \(message)"
264+
case .invalidXCFramework(let message):
265+
return "Invalid xcframework. \(message)"
223266
case .invalidTemplates(let message):
224267
return "Invalid templates. \(message)"
225268
case .invalidOutput(let message):

Sourcery/Sourcery.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ public class Sourcery {
9595
paths.append(file)
9696
modules.append(target.module)
9797
}
98+
for framework in target.xcframeworks {
99+
paths.append(framework.swiftInterfacePath)
100+
modules.append(target.module)
101+
}
98102
}
99103
}
100104
result = try self.parse(from: paths, forceParse: forceParse, parseDocumentation: parseDocumentation, modules: modules, requiresFileParserCopy: hasSwiftTemplates)

SourceryUtils/Sources/Path+Extensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extension Path {
5252
}
5353

5454
public var isSwiftSourceFile: Bool {
55-
return !self.isDirectory && self.extension == "swift"
55+
return !self.isDirectory && (self.extension == "swift" || self.extension == "swiftinterface")
5656
}
5757

5858
public func hasExtension(as string: String) -> Bool {

docs/usage.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,15 @@ <h4 id='sources' class='heading'>Sources</h4>
293293
<span class="pi">-</span> <span class="s">&lt;source file path&gt;</span>
294294
</code></pre>
295295

296-
<p>Or you can provide project which will be scanned and which source files will be processed. You can use several <code>project</code> or <code>target</code> objects to scan multiple targets from one project or to scan multiple projects.</p>
296+
<p>Or you can provide project which will be scanned and which source files will be processed. You can use several <code>project</code> or <code>target</code> 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 <code>swiftinterface</code> files.</p>
297297
<pre class="highlight yaml"><code><span class="na">project</span><span class="pi">:</span>
298298
<span class="na">file</span><span class="pi">:</span> <span class="s">&lt;path to xcodeproj file&gt;</span>
299299
<span class="na">target</span><span class="pi">:</span>
300300
<span class="na">name</span><span class="pi">:</span> <span class="s">&lt;target name&gt;</span>
301301
<span class="na">module</span><span class="pi">:</span> <span class="s">&lt;module name&gt; //required if different from target name</span>
302+
<span class="na">xcframeworks</span><span class="pi">:</span>
303+
<span class="pi">-</span> <span class="s">&lt;path to xcframework file&gt;</span>
304+
<span class="pi">-</span> <span class="s">&lt;path to xcframework file&gt;</span>
302305
</code></pre>
303306
<h4 id='excluding-sources-or-templates' class='heading'>Excluding sources or templates</h4>
304307

guides/Usage.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,17 @@ sources:
8787
- <source file path>
8888
```
8989

90-
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.
90+
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.
9191

9292
```yaml
9393
project:
9494
file: <path to xcodeproj file>
9595
target:
9696
name: <target name>
9797
module: <module name> //required if different from target name
98+
xcframeworks:
99+
- <path to xcframework file>
100+
- <path to xcframework file>
98101
```
99102

100103
#### Excluding sources or templates

0 commit comments

Comments
 (0)