Initial commit
This commit is contained in:
commit
030323ce7f
|
@ -0,0 +1,9 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/config/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -0,0 +1,76 @@
|
|||
excluded:
|
||||
- .build
|
||||
disabled_rules:
|
||||
- nesting
|
||||
opt_in_rules:
|
||||
- anonymous_argument_in_multiline_closure
|
||||
- array_init
|
||||
- capture_variable
|
||||
- collection_alignment
|
||||
- conditional_returns_on_newline
|
||||
- contains_over_filter_count
|
||||
- contains_over_filter_is_empty
|
||||
- contains_over_first_not_nil
|
||||
- contains_over_range_nil_comparison
|
||||
- convenience_type
|
||||
- discarded_notification_center_observer
|
||||
- discouraged_assert
|
||||
- discouraged_none_name
|
||||
- discouraged_object_literal
|
||||
- discouraged_optional_boolean
|
||||
- empty_collection_literal
|
||||
- empty_count
|
||||
- empty_string
|
||||
- empty_xctest_method
|
||||
- explicit_init
|
||||
- fallthrough
|
||||
- fatal_error_message
|
||||
- file_name_no_space
|
||||
- first_where
|
||||
- flatmap_over_map_reduce
|
||||
- identical_operands
|
||||
- implicitly_unwrapped_optional
|
||||
- joined_default_parameter
|
||||
- last_where
|
||||
- literal_expression_end_indentation
|
||||
- lower_acl_than_parent
|
||||
- modifier_order
|
||||
- number_separator
|
||||
- operator_usage_whitespace
|
||||
- overridden_super_call
|
||||
- pattern_matching_keywords
|
||||
- prefer_self_in_static_references
|
||||
- prefer_self_type_over_type_of_self
|
||||
- prefer_zero_over_explicit_init
|
||||
- prohibited_interface_builder
|
||||
- prohibited_super_call
|
||||
- reduce_into
|
||||
- redundant_nil_coalescing
|
||||
- redundant_type_annotation
|
||||
- single_test_class
|
||||
- sorted_first_last
|
||||
- sorted_imports
|
||||
- static_operator
|
||||
- switch_case_on_newline
|
||||
- test_case_accessibility
|
||||
- toggle_bool
|
||||
- trailing_closure
|
||||
- unneeded_parentheses_in_closure_argument
|
||||
- untyped_error_in_catch
|
||||
- vertical_parameter_alignment_on_call
|
||||
- yoda_condition
|
||||
line_length:
|
||||
warning: 150
|
||||
error: 175
|
||||
ignores_comments: true
|
||||
type_name:
|
||||
max_length:
|
||||
warning: 60
|
||||
error: 60
|
||||
identifier_name:
|
||||
allowed_symbols: "_"
|
||||
max_length:
|
||||
warning: 60
|
||||
error: 60
|
||||
min_length:
|
||||
warning: 1
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,333 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1410"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "graph-deps"
|
||||
BuildableName = "graph-deps"
|
||||
BlueprintName = "graph-deps"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "GraphDepsTests"
|
||||
BuildableName = "GraphDepsTests"
|
||||
BlueprintName = "GraphDepsTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "GraphDeps"
|
||||
BuildableName = "GraphDeps"
|
||||
BlueprintName = "GraphDeps"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Graph"
|
||||
BuildableName = "Graph"
|
||||
BlueprintName = "Graph"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "XcodeProjectReader"
|
||||
BuildableName = "XcodeProjectReader"
|
||||
BlueprintName = "XcodeProjectReader"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "XcodeProjectParser"
|
||||
BuildableName = "XcodeProjectParser"
|
||||
BlueprintName = "XcodeProjectParser"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PackageSwiftParser"
|
||||
BuildableName = "PackageSwiftParser"
|
||||
BlueprintName = "PackageSwiftParser"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "ShellCommandRunner"
|
||||
BuildableName = "ShellCommandRunner"
|
||||
BlueprintName = "ShellCommandRunner"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PackageSwiftFileParser"
|
||||
BuildableName = "PackageSwiftFileParser"
|
||||
BlueprintName = "PackageSwiftFileParser"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PackageSwiftFileParserLive"
|
||||
BuildableName = "PackageSwiftFileParserLive"
|
||||
BlueprintName = "PackageSwiftFileParserLive"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "XcodeProjectParserLive"
|
||||
BuildableName = "XcodeProjectParserLive"
|
||||
BlueprintName = "XcodeProjectParserLive"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "ShellCommandRunnerLive"
|
||||
BuildableName = "ShellCommandRunnerLive"
|
||||
BlueprintName = "ShellCommandRunnerLive"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "GraphDeps_PackageSwiftFileParserLiveTests"
|
||||
BuildableName = "GraphDeps_PackageSwiftFileParserLiveTests"
|
||||
BlueprintName = "GraphDeps_PackageSwiftFileParserLiveTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PackageSwiftFileReader"
|
||||
BuildableName = "PackageSwiftFileReader"
|
||||
BlueprintName = "PackageSwiftFileReader"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PackageSwiftFileReaderLive"
|
||||
BuildableName = "PackageSwiftFileReaderLive"
|
||||
BlueprintName = "PackageSwiftFileReaderLive"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DumpPackageService"
|
||||
BuildableName = "DumpPackageService"
|
||||
BlueprintName = "DumpPackageService"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DumpPackageServiceLive"
|
||||
BuildableName = "DumpPackageServiceLive"
|
||||
BlueprintName = "DumpPackageServiceLive"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "GraphDepsTests"
|
||||
BuildableName = "GraphDepsTests"
|
||||
BlueprintName = "GraphDepsTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "PackageSwiftFileParserLiveTests"
|
||||
BuildableName = "PackageSwiftFileParserLiveTests"
|
||||
BlueprintName = "PackageSwiftFileParserLiveTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DumpPackageServiceLiveTests"
|
||||
BuildableName = "DumpPackageServiceLiveTests"
|
||||
BlueprintName = "DumpPackageServiceLiveTests"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
viewDebuggingEnabled = "No">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "graph-deps"
|
||||
BuildableName = "graph-deps"
|
||||
BlueprintName = "graph-deps"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "graph-deps"
|
||||
BuildableName = "graph-deps"
|
||||
BlueprintName = "graph-deps"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "aexml",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/tadija/AEXML.git",
|
||||
"state" : {
|
||||
"revision" : "38f7d00b23ecd891e1ee656fa6aeebd6ba04ecc3",
|
||||
"version" : "4.6.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "pathkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kylef/PathKit.git",
|
||||
"state" : {
|
||||
"revision" : "3bfd2737b700b9a36565a8c94f4ad2b050a5e574",
|
||||
"version" : "1.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "spectre",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/kylef/Spectre.git",
|
||||
"state" : {
|
||||
"revision" : "26cc5e9ae0947092c7139ef7ba612e34646086c7",
|
||||
"version" : "0.10.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-argument-parser",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-argument-parser",
|
||||
"state" : {
|
||||
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d",
|
||||
"version" : "1.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "xcodeproj",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/tuist/XcodeProj.git",
|
||||
"state" : {
|
||||
"revision" : "b6de1bfe021b861c94e7c83821b595083f74b997",
|
||||
"version" : "8.8.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// swift-tools-version: 5.7
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "GraphDeps",
|
||||
platforms: [.macOS(.v13)],
|
||||
products: [
|
||||
.executable(name: "graph-deps", targets: ["GraphDeps"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.0"),
|
||||
.package(url: "https://github.com/tuist/XcodeProj.git", .upToNextMajor(from: "8.8.0"))
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(name: "GraphDeps", dependencies: [
|
||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||
"DumpPackageService",
|
||||
"DumpPackageServiceLive",
|
||||
"Graph",
|
||||
"PackageSwiftFileParser",
|
||||
"PackageSwiftFileParserLive",
|
||||
"ShellCommandRunner",
|
||||
"ShellCommandRunnerLive",
|
||||
"XcodeProjectParser",
|
||||
"XcodeProjectParserLive"
|
||||
]),
|
||||
.target(name: "Graph"),
|
||||
.target(name: "PackageSwiftFileParser"),
|
||||
.target(name: "PackageSwiftFileParserLive", dependencies: [
|
||||
"DumpPackageService",
|
||||
"PackageSwiftFileParser"
|
||||
]),
|
||||
.target(name: "DumpPackageService"),
|
||||
.target(name: "DumpPackageServiceLive", dependencies: [
|
||||
"DumpPackageService",
|
||||
"ShellCommandRunner"
|
||||
]),
|
||||
.target(name: "ShellCommandRunner"),
|
||||
.target(name: "ShellCommandRunnerLive", dependencies: [
|
||||
"ShellCommandRunner"
|
||||
]),
|
||||
.target(name: "XcodeProjectParser"),
|
||||
.target(name: "XcodeProjectParserLive", dependencies: [
|
||||
.product(name: "XcodeProj", package: "XcodeProj"),
|
||||
"XcodeProjectParser"
|
||||
]),
|
||||
.testTarget(name: "DumpPackageServiceLiveTests", dependencies: [
|
||||
"DumpPackageServiceLive",
|
||||
"ShellCommandRunner"
|
||||
]),
|
||||
.testTarget(name: "PackageSwiftFileParserLiveTests", dependencies: [
|
||||
"DumpPackageService",
|
||||
"PackageSwiftFileParser",
|
||||
"PackageSwiftFileParserLive"
|
||||
], resources: [.copy("MockData")])
|
||||
]
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
import Foundation
|
||||
|
||||
public protocol DumpPackageService {
|
||||
func dumpPackageForSwiftPackageFile(at fileURL: URL) throws -> Data
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import DumpPackageService
|
||||
import Foundation
|
||||
import ShellCommandRunner
|
||||
|
||||
public enum DumpPackageServiceLiveError: LocalizedError {
|
||||
case invalidPackageSwiftFileURL
|
||||
case unexpectedTerminationStatus(Int32)
|
||||
case failedConvertingStringToData
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidPackageSwiftFileURL:
|
||||
return "Expected URL to a Package.swift file"
|
||||
case .unexpectedTerminationStatus(let status):
|
||||
return "Unexpected termination status: \(status)"
|
||||
case .failedConvertingStringToData:
|
||||
return "Failed converting string to data"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct DumpPackageServiceLive: DumpPackageService {
|
||||
private let shellCommandRunner: ShellCommandRunner
|
||||
|
||||
public init(shellCommandRunner: ShellCommandRunner) {
|
||||
self.shellCommandRunner = shellCommandRunner
|
||||
}
|
||||
|
||||
public func dumpPackageForSwiftPackageFile(at fileURL: URL) throws -> Data {
|
||||
guard fileURL.lastPathComponent == "Package.swift" else {
|
||||
throw DumpPackageServiceLiveError.invalidPackageSwiftFileURL
|
||||
}
|
||||
let directoryURL = fileURL.deletingLastPathComponent()
|
||||
return try dumpPackage(at: directoryURL)
|
||||
}
|
||||
}
|
||||
|
||||
private extension DumpPackageServiceLive {
|
||||
private func dumpPackage(at directoryURL: URL) throws -> Data {
|
||||
let output = shellCommandRunner.run(withArguments: ["swift", "package", "dump-package"], fromDirectoryURL: directoryURL)
|
||||
guard output.status == 0 else {
|
||||
throw DumpPackageServiceLiveError.unexpectedTerminationStatus(output.status)
|
||||
}
|
||||
guard let data = output.message.data(using: .utf8) else {
|
||||
throw DumpPackageServiceLiveError.failedConvertingStringToData
|
||||
}
|
||||
return data
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
public final class Node {
|
||||
public let name: String
|
||||
public private(set) var children: [Node]
|
||||
|
||||
public init(name: String, children: [Node] = []) {
|
||||
self.name = name
|
||||
self.children = children
|
||||
}
|
||||
|
||||
public func addChild(_ node: Node) {
|
||||
children.append(node)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import DumpPackageService
|
||||
import DumpPackageServiceLive
|
||||
import PackageSwiftFileParser
|
||||
import PackageSwiftFileParserLive
|
||||
import ShellCommandRunner
|
||||
import ShellCommandRunnerLive
|
||||
import XcodeProjectParser
|
||||
import XcodeProjectParserLive
|
||||
|
||||
public enum CompositionRoot {
|
||||
static var xcodeProjectParser: XcodeProjectParser {
|
||||
return XcodeProjectParserLive(packageSwiftFileParser: packageSwiftFileParser)
|
||||
}
|
||||
}
|
||||
|
||||
private extension CompositionRoot {
|
||||
private static var packageSwiftFileParser: PackageSwiftFileParser {
|
||||
return PackageSwiftFileParserLive(dumpPackageService: dumpPackageService)
|
||||
}
|
||||
|
||||
private static var dumpPackageService: DumpPackageService {
|
||||
return DumpPackageServiceLive(shellCommandRunner: shellCommandRunner)
|
||||
}
|
||||
|
||||
private static var shellCommandRunner: ShellCommandRunner {
|
||||
return ShellCommandRunnerLive()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import ArgumentParser
|
||||
import Foundation
|
||||
|
||||
@main
|
||||
struct GraphDeps: ParsableCommand {
|
||||
@Argument(help: "The Xcode project to parse.")
|
||||
var input: String
|
||||
|
||||
static let configuration = CommandConfiguration(
|
||||
abstract: "A Swift command-line tool to graph package dependencies"
|
||||
)
|
||||
|
||||
func run() throws {}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
extension PackageSwiftFile {
|
||||
public enum Dependency: Equatable {
|
||||
public struct SourceControlParameters: Equatable {
|
||||
public let identity: String
|
||||
|
||||
public init(identity: String) {
|
||||
self.identity = identity
|
||||
}
|
||||
}
|
||||
|
||||
public struct FileSystemParameters: Equatable {
|
||||
public let identity: String
|
||||
public let path: String
|
||||
public let packageSwiftFile: PackageSwiftFile
|
||||
|
||||
public init(identity: String, path: String, packageSwiftFile: PackageSwiftFile) {
|
||||
self.identity = identity
|
||||
self.path = path
|
||||
self.packageSwiftFile = packageSwiftFile
|
||||
}
|
||||
}
|
||||
|
||||
case sourceControl(SourceControlParameters)
|
||||
case fileSystem(FileSystemParameters)
|
||||
|
||||
public static func sourceControl(identity: String) -> Self {
|
||||
let parameters = SourceControlParameters(identity: identity)
|
||||
return .sourceControl(parameters)
|
||||
}
|
||||
|
||||
public static func fileSystem(identity: String, path: String, packageSwiftFile: PackageSwiftFile) -> Self {
|
||||
let parameters = FileSystemParameters(identity: identity, path: path, packageSwiftFile: packageSwiftFile)
|
||||
return .fileSystem(parameters)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
public extension PackageSwiftFile.Target {
|
||||
enum Dependency: Equatable {
|
||||
public struct NameParameters: Equatable {
|
||||
public let name: String
|
||||
|
||||
public init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
|
||||
public struct ProductInPackageParameters: Equatable {
|
||||
public let name: String
|
||||
public let packageName: String
|
||||
|
||||
public init(name: String, packageName: String) {
|
||||
self.name = name
|
||||
self.packageName = packageName
|
||||
}
|
||||
}
|
||||
|
||||
case name(NameParameters)
|
||||
case productInPackage(ProductInPackageParameters)
|
||||
|
||||
public static func name(_ name: String) -> Self {
|
||||
return .name(.init(name: name))
|
||||
}
|
||||
|
||||
public static func product(_ name: String, inPackage package: String) -> Self {
|
||||
return .productInPackage(.init(name: name, packageName: package))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
public extension PackageSwiftFile {
|
||||
struct Target: Equatable {
|
||||
public let name: String
|
||||
public let dependencies: [Dependency]
|
||||
|
||||
public init(name: String, dependencies: [Dependency] = []) {
|
||||
self.name = name
|
||||
self.dependencies = dependencies
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
public struct PackageSwiftFile: Equatable {
|
||||
public let name: String
|
||||
public let targets: [Target]
|
||||
public let dependencies: [Dependency]
|
||||
|
||||
public init(name: String, targets: [Target] = [], dependencies: [Dependency] = []) {
|
||||
self.name = name
|
||||
self.targets = targets
|
||||
self.dependencies = dependencies
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import Foundation
|
||||
|
||||
public protocol PackageSwiftFileParser {
|
||||
func parseFile(at fileURL: URL) throws -> PackageSwiftFile
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
extension IntermediatePackageSwiftFile {
|
||||
enum Dependency: Decodable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case sourceControl
|
||||
case fileSystem
|
||||
}
|
||||
|
||||
struct SourceControlParameters: Decodable {
|
||||
let identity: String
|
||||
}
|
||||
|
||||
struct FileSystemParameters: Decodable {
|
||||
let identity: String
|
||||
let path: String
|
||||
}
|
||||
|
||||
case sourceControl(SourceControlParameters)
|
||||
case fileSystem(FileSystemParameters)
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
if container.allKeys.contains(CodingKeys.sourceControl) {
|
||||
self = try .decodeSourceControl(using: container)
|
||||
} else if container.allKeys.contains(CodingKeys.fileSystem) {
|
||||
self = try .decodeFileSystem(using: container)
|
||||
} else {
|
||||
let keysString = container.allKeys.map(\.stringValue).joined(separator: ", ")
|
||||
let debugDescription = "Unsupported keys: " + keysString
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension IntermediatePackageSwiftFile.Dependency {
|
||||
private static func decodeSourceControl(using container: KeyedDecodingContainer<Self.CodingKeys>) throws -> Self {
|
||||
let parametersContainer = try container.decode([SourceControlParameters].self, forKey: .sourceControl)
|
||||
guard parametersContainer.count == 1 else {
|
||||
let debugDescription = "Expected to decode exactly 1 parameter object but found \(parametersContainer.count)"
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
return .sourceControl(parametersContainer[0])
|
||||
}
|
||||
|
||||
private static func decodeFileSystem(using container: KeyedDecodingContainer<Self.CodingKeys>) throws -> Self {
|
||||
let parametersContainer = try container.decode([FileSystemParameters].self, forKey: .fileSystem)
|
||||
guard parametersContainer.count == 1 else {
|
||||
let debugDescription = "Expected to decode exactly 1 parameter object but found \(parametersContainer.count)"
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
return .fileSystem(parametersContainer[0])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
extension IntermediatePackageSwiftFile.Target {
|
||||
enum Dependency: Decodable {
|
||||
private enum CodingKeys: CodingKey {
|
||||
case byName
|
||||
case product
|
||||
}
|
||||
|
||||
struct ByNameParameters {
|
||||
let name: String
|
||||
}
|
||||
|
||||
struct ProductParameters {
|
||||
let name: String
|
||||
let package: String
|
||||
}
|
||||
|
||||
case byName(ByNameParameters)
|
||||
case product(ProductParameters)
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
if container.allKeys.contains(CodingKeys.byName) {
|
||||
self = try .decodeByName(using: container)
|
||||
} else if container.allKeys.contains(CodingKeys.product) {
|
||||
self = try .decodeProduct(using: container)
|
||||
} else {
|
||||
let keysString = container.allKeys.map(\.stringValue).joined(separator: ", ")
|
||||
let debugDescription = "Unsupported keys: " + keysString
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension IntermediatePackageSwiftFile.Target.Dependency {
|
||||
private static func decodeByName(using container: KeyedDecodingContainer<Self.CodingKeys>) throws -> Self {
|
||||
let values = try container.decode([String?].self, forKey: .byName)
|
||||
guard values.count >= 1 else {
|
||||
let debugDescription = "Expected to decode at least 1 string but found \(values.count)"
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
guard case let .some(name) = values[0] else {
|
||||
let debugDescription = "Expected library name to be non-null"
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
let parameters = ByNameParameters(name: name)
|
||||
return .byName(parameters)
|
||||
}
|
||||
|
||||
private static func decodeProduct(using container: KeyedDecodingContainer<Self.CodingKeys>) throws -> Self {
|
||||
let values = try container.decode([String?].self, forKey: .product)
|
||||
guard values.count >= 2 else {
|
||||
let debugDescription = "Expected to decode at least 2 strings but found \(values.count)"
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
guard case let .some(name) = values[0] else {
|
||||
let debugDescription = "Expected library name to be non-null"
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
guard case let .some(package) = values[1] else {
|
||||
let debugDescription = "Expected package name to be non-null"
|
||||
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: debugDescription))
|
||||
}
|
||||
let parameters = ProductParameters(name: name, package: package)
|
||||
return .product(parameters)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
extension IntermediatePackageSwiftFile {
|
||||
struct Target: Decodable {
|
||||
let name: String
|
||||
let dependencies: [Dependency]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
struct IntermediatePackageSwiftFile: Decodable {
|
||||
let name: String
|
||||
let targets: [Target]
|
||||
let dependencies: [Dependency]
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
import DumpPackageService
|
||||
import Foundation
|
||||
import PackageSwiftFileParser
|
||||
|
||||
struct PackageSwiftFileMapper {
|
||||
private let dumpPackageService: DumpPackageService
|
||||
private let packageSwiftFileParser: PackageSwiftFileParser
|
||||
|
||||
init(dumpPackageService: DumpPackageService, packageSwiftFileParser: PackageSwiftFileParser) {
|
||||
self.dumpPackageService = dumpPackageService
|
||||
self.packageSwiftFileParser = packageSwiftFileParser
|
||||
}
|
||||
|
||||
func map(_ intermediate: IntermediatePackageSwiftFile) throws -> PackageSwiftFile {
|
||||
let targets = intermediate.targets.map(map)
|
||||
let dependencies = try intermediate.dependencies.map(map)
|
||||
return PackageSwiftFile(name: intermediate.name, targets: targets, dependencies: dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
private extension PackageSwiftFileMapper {
|
||||
private func map(_ intermediate: IntermediatePackageSwiftFile.Target) -> PackageSwiftFile.Target {
|
||||
let dependencies = intermediate.dependencies.map(map)
|
||||
return PackageSwiftFile.Target(name: intermediate.name, dependencies: dependencies)
|
||||
}
|
||||
|
||||
private func map(_ intermediate: IntermediatePackageSwiftFile.Target.Dependency) -> PackageSwiftFile.Target.Dependency {
|
||||
switch intermediate {
|
||||
case .byName(let parameters):
|
||||
return .name(parameters.name)
|
||||
case .product(let parameters):
|
||||
return .product(parameters.name, inPackage: parameters.package)
|
||||
}
|
||||
}
|
||||
|
||||
private func map(_ intermediate: IntermediatePackageSwiftFile.Dependency) throws -> PackageSwiftFile.Dependency {
|
||||
switch intermediate {
|
||||
case .sourceControl(let parameters):
|
||||
return .sourceControl(identity: parameters.identity)
|
||||
case .fileSystem(let parameters):
|
||||
let fileURL = URL(filePath: parameters.path).appending(path: "Package.swift")
|
||||
let contents = try dumpPackageService.dumpPackageForSwiftPackageFile(at: fileURL)
|
||||
let packageSwiftFile = try packageSwiftFileParser.parseFile(at: fileURL)
|
||||
return .fileSystem(identity: parameters.identity, path: parameters.path, packageSwiftFile: packageSwiftFile)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import DumpPackageService
|
||||
import Foundation
|
||||
import PackageSwiftFileParser
|
||||
|
||||
public struct PackageSwiftFileParserLive: PackageSwiftFileParser {
|
||||
private let dumpPackageService: DumpPackageService
|
||||
|
||||
public init(dumpPackageService: DumpPackageService) {
|
||||
self.dumpPackageService = dumpPackageService
|
||||
}
|
||||
|
||||
public func parseFile(at fileURL: URL) throws -> PackageSwiftFile {
|
||||
let contents = try dumpPackageService.dumpPackageForSwiftPackageFile(at: fileURL)
|
||||
let decoder = JSONDecoder()
|
||||
let intermediate = try decoder.decode(IntermediatePackageSwiftFile.self, from: contents)
|
||||
let mapper = PackageSwiftFileMapper(dumpPackageService: dumpPackageService, packageSwiftFileParser: self)
|
||||
return try mapper.map(intermediate)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
public struct ShellCommandOutput {
|
||||
public let status: Int32
|
||||
public let message: String
|
||||
|
||||
public init(status: Int32, message: String) {
|
||||
self.status = status
|
||||
self.message = message
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import Foundation
|
||||
|
||||
public protocol ShellCommandRunner {
|
||||
func run(withArguments arguments: [String], fromDirectoryURL directoryURL: URL) -> ShellCommandOutput
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import Foundation
|
||||
import ShellCommandRunner
|
||||
|
||||
public struct ShellCommandRunnerLive: ShellCommandRunner {
|
||||
public init() {}
|
||||
|
||||
public func run(withArguments arguments: [String], fromDirectoryURL directoryURL: URL) -> ShellCommandOutput {
|
||||
let task = Process()
|
||||
let pipe = Pipe()
|
||||
task.currentDirectoryURL = directoryURL
|
||||
task.standardOutput = pipe
|
||||
task.standardError = pipe
|
||||
task.arguments = ["-c", arguments.joined(separator: " ")]
|
||||
task.launchPath = "/bin/zsh"
|
||||
task.standardInput = nil
|
||||
task.launch()
|
||||
task.waitUntilExit()
|
||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
let message = String(data: data, encoding: .utf8)!
|
||||
let status = task.terminationStatus
|
||||
return ShellCommandOutput(status: status, message: message)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import Foundation
|
||||
|
||||
public extension XcodeProject {
|
||||
enum SwiftPackage {
|
||||
public struct LocalParameters {
|
||||
public let name: String
|
||||
public let fileURL: URL
|
||||
|
||||
public init(name: String, fileURL: URL) {
|
||||
self.name = name
|
||||
self.fileURL = fileURL
|
||||
}
|
||||
}
|
||||
|
||||
public struct RemoteParameters {
|
||||
public let name: String
|
||||
public let repositoryURL: URL
|
||||
|
||||
public init(name: String, repositoryURL: URL) {
|
||||
self.name = name
|
||||
self.repositoryURL = repositoryURL
|
||||
}
|
||||
}
|
||||
|
||||
case local(LocalParameters)
|
||||
case remote(RemoteParameters)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import Foundation
|
||||
|
||||
extension XcodeProject {
|
||||
public struct Target {
|
||||
public let name: String
|
||||
public let packageProductDependencies: [String]
|
||||
|
||||
public init(name: String, packageProductDependencies: [String]) {
|
||||
self.name = name
|
||||
self.packageProductDependencies = packageProductDependencies
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import Foundation
|
||||
|
||||
public struct XcodeProject {
|
||||
public let name: String
|
||||
public let targets: [Target]
|
||||
public let swiftPackages: [SwiftPackage]
|
||||
|
||||
public init(name: String, targets: [Target] = [], swiftPackages: [SwiftPackage] = []) {
|
||||
self.name = name
|
||||
self.targets = targets
|
||||
self.swiftPackages = swiftPackages
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import Foundation
|
||||
|
||||
public protocol XcodeProjectParser {
|
||||
func parseProject(at fileURL: URL) throws -> XcodeProject
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import Foundation
|
||||
import PackageSwiftFileParser
|
||||
import PathKit
|
||||
import XcodeProj
|
||||
import XcodeProjectParser
|
||||
|
||||
public struct XcodeProjectParserLive: XcodeProjectParser {
|
||||
private let packageSwiftFileParser: PackageSwiftFileParser
|
||||
|
||||
public init(packageSwiftFileParser: PackageSwiftFileParser) {
|
||||
self.packageSwiftFileParser = packageSwiftFileParser
|
||||
}
|
||||
|
||||
public func parseProject(at fileURL: URL) throws -> XcodeProject {
|
||||
let path = Path(fileURL.relativePath)
|
||||
let project = try XcodeProj(path: path)
|
||||
let sourceRoot = fileURL.deletingLastPathComponent()
|
||||
let remoteSwiftPackages = remoteSwiftPackages(in: project)
|
||||
let localSwiftPackages = try localSwiftPackages(in: project, atSourceRoot: sourceRoot)
|
||||
return XcodeProject(
|
||||
name: fileURL.lastPathComponent,
|
||||
targets: targets(in: project),
|
||||
swiftPackages: remoteSwiftPackages + localSwiftPackages
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private extension XcodeProjectParserLive {
|
||||
func targets(in project: XcodeProj) -> [XcodeProject.Target] {
|
||||
return project.pbxproj.nativeTargets.map { target in
|
||||
let packageProductDependencies = target.packageProductDependencies.map(\.productName)
|
||||
return .init(name: target.name, packageProductDependencies: packageProductDependencies)
|
||||
}
|
||||
}
|
||||
|
||||
func remoteSwiftPackages(in project: XcodeProj) -> [XcodeProject.SwiftPackage] {
|
||||
return project.pbxproj.nativeTargets.reduce(into: []) { targetResult, target in
|
||||
targetResult += target.dependencies.reduce(into: []) { dependencyResult, dependency in
|
||||
guard let package = dependency.product?.package, let packageName = package.name else {
|
||||
return
|
||||
}
|
||||
guard let rawRepositoryURL = package.repositoryURL, let repositoryURL = URL(string: rawRepositoryURL) else {
|
||||
return
|
||||
}
|
||||
dependencyResult.append(.remote(.init(name: packageName, repositoryURL: repositoryURL)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func localSwiftPackages(in project: XcodeProj, atSourceRoot sourceRoot: URL) throws -> [XcodeProject.SwiftPackage] {
|
||||
return []
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
@testable import DumpPackageServiceLive
|
||||
import XCTest
|
||||
|
||||
final class DumpPackageServiceLiveTests: XCTestCase {
|
||||
func testThrowsWhenReceivingInvalidPackageSwiftFileURL() throws {
|
||||
let shellCommandRunner = ShellCommandRunnerMock()
|
||||
let service = DumpPackageServiceLive(shellCommandRunner: shellCommandRunner)
|
||||
let fileURL = URL(fileURLWithPath: "/Users/john/Mock/NotAPackageSwiftFile")
|
||||
XCTAssertThrowsError(try service.dumpPackageForSwiftPackageFile(at: fileURL))
|
||||
}
|
||||
|
||||
func testInvokesDumpPackageCommandOnSwiftCLI() throws {
|
||||
let shellCommandRunner = ShellCommandRunnerMock()
|
||||
let service = DumpPackageServiceLive(shellCommandRunner: shellCommandRunner)
|
||||
let fileURL = URL(fileURLWithPath: "/Users/john/Mock/Package.swift")
|
||||
_ = try service.dumpPackageForSwiftPackageFile(at: fileURL)
|
||||
XCTAssertEqual(shellCommandRunner.latestArguments, ["swift", "package", "dump-package"])
|
||||
}
|
||||
|
||||
func testSetsCurrentDirectoryToSwiftPackage() throws {
|
||||
let shellCommandRunner = ShellCommandRunnerMock()
|
||||
let service = DumpPackageServiceLive(shellCommandRunner: shellCommandRunner)
|
||||
let fileURL = URL(fileURLWithPath: "/Users/john/Mock/Package.swift")
|
||||
_ = try service.dumpPackageForSwiftPackageFile(at: fileURL)
|
||||
XCTAssertEqual(shellCommandRunner.latestDirectoryURL, URL(filePath: "/Users/john/Mock/"))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import Foundation
|
||||
import ShellCommandRunner
|
||||
|
||||
final class ShellCommandRunnerMock: ShellCommandRunner {
|
||||
private(set) var latestArguments: [String]?
|
||||
private(set) var latestDirectoryURL: URL?
|
||||
|
||||
func run(withArguments arguments: [String], fromDirectoryURL directoryURL: URL) -> ShellCommandOutput {
|
||||
latestArguments = arguments
|
||||
latestDirectoryURL = directoryURL
|
||||
return ShellCommandOutput(status: 0, message: "Success")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import DumpPackageService
|
||||
import Foundation
|
||||
|
||||
struct DumpPackageServiceMock: DumpPackageService {
|
||||
private let fileURLMap: [URL: URL]
|
||||
|
||||
init(fileURLMap: [URL: URL] = [:]) {
|
||||
self.fileURLMap = fileURLMap
|
||||
}
|
||||
|
||||
func dumpPackageForSwiftPackageFile(at fileURL: URL) throws -> Data {
|
||||
let mappedFileURL = fileURLMap[fileURL] ?? fileURL
|
||||
return try Data(contentsOf: mappedFileURL)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"cLanguageStandard" : null,
|
||||
"cxxLanguageStandard" : null,
|
||||
"dependencies" : [
|
||||
|
||||
],
|
||||
"name" : "HexColor",
|
||||
"packageKind" : {
|
||||
"root" : [
|
||||
"/Users/simon/Developer/Foo/HexColor"
|
||||
]
|
||||
},
|
||||
"pkgConfig" : null,
|
||||
"platforms" : [
|
||||
{
|
||||
"options" : [
|
||||
|
||||
],
|
||||
"platformName" : "ios",
|
||||
"version" : "16.0"
|
||||
},
|
||||
{
|
||||
"options" : [
|
||||
|
||||
],
|
||||
"platformName" : "maccatalyst",
|
||||
"version" : "16.0"
|
||||
}
|
||||
],
|
||||
"products" : [
|
||||
{
|
||||
"name" : "ColorCategories",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ColorCategories"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"providers" : null,
|
||||
"swiftLanguageVersions" : null,
|
||||
"targets" : [
|
||||
{
|
||||
"dependencies" : [
|
||||
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ColorCategories",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ColorCategories",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ColorCategoriesTests",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "test"
|
||||
}
|
||||
],
|
||||
"toolsVersion" : {
|
||||
"_version" : "5.7.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,622 @@
|
|||
{
|
||||
"cLanguageStandard" : null,
|
||||
"cxxLanguageStandard" : null,
|
||||
"dependencies" : [
|
||||
{
|
||||
"sourceControl" : [
|
||||
{
|
||||
"identity" : "runestone",
|
||||
"location" : {
|
||||
"remote" : [
|
||||
"git@github.com:simonbs/Runestone.git"
|
||||
]
|
||||
},
|
||||
"productFilter" : null,
|
||||
"requirement" : {
|
||||
"branch" : [
|
||||
"main"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fileSystem" : [
|
||||
{
|
||||
"identity" : "hexcolor",
|
||||
"path" : "/Users/simon/Developer/Foo/HexColor",
|
||||
"productFilter" : null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"name" : "ScriptBrowserFeature",
|
||||
"packageKind" : {
|
||||
"root" : [
|
||||
"/Users/simon/Developer/Foo/ScriptBrowserFeature"
|
||||
]
|
||||
},
|
||||
"pkgConfig" : null,
|
||||
"platforms" : [
|
||||
{
|
||||
"options" : [
|
||||
|
||||
],
|
||||
"platformName" : "ios",
|
||||
"version" : "16.0"
|
||||
},
|
||||
{
|
||||
"options" : [
|
||||
|
||||
],
|
||||
"platformName" : "maccatalyst",
|
||||
"version" : "16.0"
|
||||
}
|
||||
],
|
||||
"products" : [
|
||||
{
|
||||
"name" : "ScriptBrowserEntities",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserEntities"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserGroupsService",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserGroupsService"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserGroupsServiceMock",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserGroupsServiceMock"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserListService",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserListService"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserListServiceLive",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserListServiceLive"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserListServiceFactory",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserListServiceFactory"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserListServiceFactoryLive",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserListServiceFactoryLive"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserSearchService",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserSearchService"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserSidebarService",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserSidebarService"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserSidebarServiceLive",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserSidebarServiceLive"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name" : "ScriptBrowserUI",
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"targets" : [
|
||||
"ScriptBrowserUI"
|
||||
],
|
||||
"type" : {
|
||||
"library" : [
|
||||
"automatic"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"providers" : null,
|
||||
"swiftLanguageVersions" : null,
|
||||
"targets" : [
|
||||
{
|
||||
"dependencies" : [
|
||||
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserEntities",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserGroupsService",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserGroupsService",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserGroupsServiceMock",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserListService",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserGroupsService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserSearchService",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserListServiceLive",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListService",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserListServiceFactory",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserGroupsService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListServiceFactory",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListServiceLive",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserSearchService",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserListServiceFactoryLive",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserSearchService",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserSidebarService",
|
||||
"resources" : [
|
||||
{
|
||||
"path" : "Resources/Localizable.strings",
|
||||
"rule" : {
|
||||
"process" : {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserGroupsService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserSidebarService",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserSidebarServiceLive",
|
||||
"resources" : [
|
||||
{
|
||||
"path" : "Resources/Localizable.strings",
|
||||
"rule" : {
|
||||
"process" : {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListServiceFactory",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserSidebarService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"product" : [
|
||||
"ColorCategories",
|
||||
"HexColor",
|
||||
null,
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserUI",
|
||||
"resources" : [
|
||||
{
|
||||
"path" : "Resources/Localizable.strings",
|
||||
"rule" : {
|
||||
"process" : {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "regular"
|
||||
},
|
||||
{
|
||||
"dependencies" : [
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserEntities",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserGroupsService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserGroupsServiceMock",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListServiceFactory",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserListServiceLive",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserSearchService",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserSidebarServiceLive",
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"byName" : [
|
||||
"ScriptBrowserUI",
|
||||
null
|
||||
]
|
||||
}
|
||||
],
|
||||
"exclude" : [
|
||||
|
||||
],
|
||||
"name" : "ScriptBrowserUITests",
|
||||
"resources" : [
|
||||
|
||||
],
|
||||
"settings" : [
|
||||
|
||||
],
|
||||
"type" : "test"
|
||||
}
|
||||
],
|
||||
"toolsVersion" : {
|
||||
"_version" : "5.7.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
import PackageSwiftFileParser
|
||||
@testable import PackageSwiftFileParserLive
|
||||
import XCTest
|
||||
|
||||
final class PackageSwiftFileParserLiveTests: XCTestCase {
|
||||
private var dumpPackageService: DumpPackageServiceMock {
|
||||
return DumpPackageServiceMock(fileURLMap: [
|
||||
URL.Mock.root: Bundle.module.url(forMockDumpPackageNamed: "root"),
|
||||
URL.Mock.hexColor: Bundle.module.url(forMockDumpPackageNamed: "hexcolor")
|
||||
])
|
||||
}
|
||||
|
||||
func testParsesName() throws {
|
||||
let parser = PackageSwiftFileParserLive(dumpPackageService: dumpPackageService)
|
||||
let swiftPackageFile = try parser.parseFile(at: URL.Mock.root)
|
||||
XCTAssertEqual(swiftPackageFile.name, "ScriptBrowserFeature")
|
||||
}
|
||||
|
||||
func testParsesTargetNames() throws {
|
||||
let parser = PackageSwiftFileParserLive(dumpPackageService: dumpPackageService)
|
||||
let swiftPackageFile = try parser.parseFile(at: URL.Mock.root)
|
||||
let targetNames = swiftPackageFile.targets.map(\.name)
|
||||
XCTAssertEqual(targetNames, [
|
||||
"ScriptBrowserEntities",
|
||||
"ScriptBrowserGroupsService",
|
||||
"ScriptBrowserGroupsServiceMock",
|
||||
"ScriptBrowserListService",
|
||||
"ScriptBrowserListServiceLive",
|
||||
"ScriptBrowserListServiceFactory",
|
||||
"ScriptBrowserListServiceFactoryLive",
|
||||
"ScriptBrowserSearchService",
|
||||
"ScriptBrowserSidebarService",
|
||||
"ScriptBrowserSidebarServiceLive",
|
||||
"ScriptBrowserUI",
|
||||
"ScriptBrowserUITests"
|
||||
])
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_body_length
|
||||
func testParsesTargets() throws {
|
||||
let parser = PackageSwiftFileParserLive(dumpPackageService: dumpPackageService)
|
||||
let swiftPackageFile = try parser.parseFile(at: URL.Mock.root)
|
||||
XCTAssertEqual(swiftPackageFile.targets, [
|
||||
.init(name: "ScriptBrowserEntities", dependencies: []),
|
||||
.init(name: "ScriptBrowserGroupsService", dependencies: [
|
||||
.name("ScriptBrowserEntities")
|
||||
]),
|
||||
.init(name: "ScriptBrowserGroupsServiceMock", dependencies: [
|
||||
.name("ScriptBrowserEntities"),
|
||||
.name("ScriptBrowserGroupsService")
|
||||
]),
|
||||
.init(name: "ScriptBrowserListService", dependencies: [
|
||||
.name("ScriptBrowserEntities")
|
||||
]),
|
||||
.init(name: "ScriptBrowserListServiceLive", dependencies: [
|
||||
.name("ScriptBrowserEntities"),
|
||||
.name("ScriptBrowserGroupsService"),
|
||||
.name("ScriptBrowserListService"),
|
||||
.name("ScriptBrowserSearchService")
|
||||
]),
|
||||
.init(name: "ScriptBrowserListServiceFactory", dependencies: [
|
||||
.name("ScriptBrowserEntities"),
|
||||
.name("ScriptBrowserListService")
|
||||
]),
|
||||
.init(name: "ScriptBrowserListServiceFactoryLive", dependencies: [
|
||||
.name("ScriptBrowserEntities"),
|
||||
.name("ScriptBrowserGroupsService"),
|
||||
.name("ScriptBrowserListServiceFactory"),
|
||||
.name("ScriptBrowserListService"),
|
||||
.name("ScriptBrowserListServiceLive"),
|
||||
.name("ScriptBrowserSearchService")
|
||||
]),
|
||||
.init(name: "ScriptBrowserSearchService", dependencies: []),
|
||||
.init(name: "ScriptBrowserSidebarService", dependencies: [
|
||||
.name("ScriptBrowserEntities")
|
||||
]),
|
||||
.init(name: "ScriptBrowserSidebarServiceLive", dependencies: [
|
||||
.name("ScriptBrowserGroupsService"),
|
||||
.name("ScriptBrowserSidebarService")
|
||||
]),
|
||||
.init(name: "ScriptBrowserUI", dependencies: [
|
||||
.name("ScriptBrowserEntities"),
|
||||
.name("ScriptBrowserListService"),
|
||||
.name("ScriptBrowserListServiceFactory"),
|
||||
.name("ScriptBrowserSidebarService"),
|
||||
.product("ColorCategories", inPackage: "HexColor")
|
||||
]),
|
||||
.init(name: "ScriptBrowserUITests", dependencies: [
|
||||
.name("ScriptBrowserEntities"),
|
||||
.name("ScriptBrowserGroupsService"),
|
||||
.name("ScriptBrowserGroupsServiceMock"),
|
||||
.name("ScriptBrowserListService"),
|
||||
.name("ScriptBrowserListServiceFactory"),
|
||||
.name("ScriptBrowserListServiceLive"),
|
||||
.name("ScriptBrowserSearchService"),
|
||||
.name("ScriptBrowserSidebarServiceLive"),
|
||||
.name("ScriptBrowserUI")
|
||||
])
|
||||
])
|
||||
}
|
||||
|
||||
func testParsesDependencies() throws {
|
||||
let parser = PackageSwiftFileParserLive(dumpPackageService: dumpPackageService)
|
||||
let swiftPackageFile = try parser.parseFile(at: URL.Mock.root)
|
||||
XCTAssertEqual(swiftPackageFile.dependencies, [
|
||||
.sourceControl(identity: "runestone"),
|
||||
.fileSystem(
|
||||
identity: "hexcolor",
|
||||
path: "/Users/simon/Developer/Foo/HexColor",
|
||||
packageSwiftFile: PackageSwiftFile(
|
||||
name: "HexColor",
|
||||
targets: [
|
||||
.init(name: "ColorCategories"),
|
||||
.init(name: "ColorCategoriesTests", dependencies: [
|
||||
.name("ColorCategories")
|
||||
])
|
||||
]
|
||||
)
|
||||
)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
private extension URL {
|
||||
enum Mock {
|
||||
static var root: URL {
|
||||
return URL(filePath: "/Users/simon/Developer/Foo/root/Package.swift")
|
||||
}
|
||||
|
||||
static var hexColor: URL {
|
||||
return URL(filePath: "/Users/simon/Developer/Foo/HexColor/Package.swift")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension Bundle {
|
||||
func url(forMockDumpPackageNamed filename: String) -> URL {
|
||||
return url(forResource: "MockData/" + filename, withExtension: "json")!
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue