@@ -4,18 +4,30 @@ import PackagePlugin
44@main
55struct 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) Unused dependencies found for \( target. name) ⚠️⚠️ \n "
64+ warningText += unusedDependencies. map { " 👉 \( $0) is an unused depdnency " }
65+ . joined ( separator: " \n " )
66+
67+ let echoTool = try context. tool ( named: " echo " )
68+ return [ . buildCommand(
69+ displayName: " Unused Dependencies Report " ,
70+ executable: echoTool. path,
71+ arguments: [ warningText] ,
72+ environment: [ : ]
73+ ) ]
4274 }
4375}
4476
0 commit comments