Skip to content

Commit 7180e2c

Browse files
authored
Merge pull request #4 from arde02/main
Add Unused Dependencies Check
2 parents ad9c8e7 + 73d42ff commit 7180e2c

2 files changed

Lines changed: 56 additions & 21 deletions

File tree

Plugins/explicitDependencyImportCheckPlugin/ExplicitDependencyImportCheckPlugin.swift

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,30 @@ import PackagePlugin
44
@main
55
struct ExplicitDependencyImportCheckPlugin: BuildToolPlugin {
66
func createBuildCommands(context: PluginContext, target: any Target) async throws -> [Command] {
7-
let dependeniesNames = findSpmTargetDependencies(fromTarget: target)
8-
let sitrepResponse = try findImportsUsedInCode(context: context, path: target.directory.string)
9-
let transitiveDependencies = sitrepResponse.subtracting(dependeniesNames)
10-
let transitiveDependenciesWithoutCommon = transitiveDependencies.subtracting(systemLibraries)
11-
guard transitiveDependenciesWithoutCommon.isEmpty == false else { return [] }
12-
return [
13-
try exportTransitiveDependenciesAsErrors(
14-
transitiveDeps: transitiveDependenciesWithoutCommon,
15-
forTarget: target,
16-
inContext: context
17-
)
18-
]
7+
let targetDependencies = findSpmTargetDependencies(fromTarget: target)
8+
let importsInCode = try findImportsUsedInCode(context: context, path: target.directory.string)
9+
let transitiveDependencies = findTransitiveDependencies(imports: importsInCode, targetDependencies: targetDependencies)
10+
let unusedTargetDependencies = findUnusedTargetDependencies(imports: importsInCode, targetDependencies: targetDependencies)
11+
12+
return (try exportTransitiveDependenciesAsErrors(
13+
transitiveDeps: transitiveDependencies,
14+
forTarget: target,
15+
inContext: context
16+
)) +
17+
(try exportUnusedDependenciesAsWarnings(
18+
unusedDependencies: unusedTargetDependencies,
19+
forTarget: target,
20+
inContext: context
21+
))
22+
}
23+
24+
func findTransitiveDependencies(imports: Set<String>, targetDependencies: Set<String>) -> Set<String> {
25+
return imports.subtracting(targetDependencies)
26+
.subtracting(systemLibraries)
27+
}
28+
29+
func findUnusedTargetDependencies(imports: Set<String>, targetDependencies: Set<String>) -> Set<String> {
30+
return targetDependencies.subtracting(imports)
1931
}
2032
}
2133

@@ -25,20 +37,40 @@ extension ExplicitDependencyImportCheckPlugin {
2537
transitiveDeps: Set<String>,
2638
forTarget target: Target,
2739
inContext context: PluginContext
28-
) throws -> Command {
29-
var transitiveDependenciesErrorText = "error: \(transitiveDeps.count) Transitive dependencies found for \(target.name) 🚨🚨🚨"
30-
for transitiveDep in transitiveDeps {
31-
transitiveDependenciesErrorText += "\n"
32-
transitiveDependenciesErrorText += "👉 \(transitiveDep) is a transitive dependency"
33-
}
40+
) throws -> [Command] {
41+
guard !transitiveDeps.isEmpty else { return [] }
42+
43+
var transitiveDependenciesErrorText = "error: \(transitiveDeps.count) Transitive dependencies found for \(target.name) 🚨🚨🚨\n"
44+
transitiveDependenciesErrorText += transitiveDeps.map { "👉 \($0) is a transitive dependency" }
45+
.joined(separator: "\n")
46+
3447
let echoTool = try context.tool(named: "echo")
35-
return .buildCommand(
48+
return [.buildCommand(
3649
displayName: "Transitive Dependencies Report",
3750
executable: echoTool.path,
3851
arguments: [transitiveDependenciesErrorText],
3952
environment: [:]
40-
)
41-
53+
)]
54+
}
55+
56+
func exportUnusedDependenciesAsWarnings(
57+
unusedDependencies: Set<String>,
58+
forTarget target: Target,
59+
inContext context: PluginContext
60+
) throws -> [Command] {
61+
guard !unusedDependencies.isEmpty else { return [] }
62+
63+
var warningText = "warning: \(unusedDependencies.count) Extraneous dependencies found for \(target.name) ⚠️⚠️\n"
64+
warningText += unusedDependencies.map { "👉 \($0) is an extraneous dependency" }
65+
.joined(separator: "\n")
66+
67+
let echoTool = try context.tool(named: "echo")
68+
return [.buildCommand(
69+
displayName: "Extraneous Dependencies Report",
70+
executable: echoTool.path,
71+
arguments: [warningText],
72+
environment: [:]
73+
)]
4274
}
4375
}
4476

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
**explicitDependencyImportCheck** is a Swift build plugin designed to help you enforce clean dependency management by ensuring that only explicitly declared dependencies are imported. Transitive dependencies can cause a range of problems, from bloated builds to fragile code. Swift provides the `--explicit-target-dependency-import-check` flag for this purpose, but it doesn’t work consistently with **XcodeBuild** – and that’s where this plugin steps in! 🚀
44

5+
This plugin also helps identify module dependencies that are unused and that can be removed from your Package.swift to speed up your builds even more!
6+
57
## 🌟 Features
68

79
- **No More Transitive Dependencies**: Catch unwanted transitive imports and keep your code cleaner, faster, and more modular.
10+
- **No More Unused Dependencies**: Catch dependencies to modules that are unused and unnecessary.
811
- **Swift Build Plugin**: Runs automatically during the Swift build process.
912
- **Easy Integration**: Just add it to your project to start using!
1013

0 commit comments

Comments
 (0)