diff --git a/CHANGELOG.md b/CHANGELOG.md index da06225a..31604a44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. `Scout` adheres to [Semantic Versioning](http://semver.org). --- +## [1.2.3](https://github.com/ABridoux/scout/tree/1.2.3) (06/07/2020) + +### Changed +- Errors now sent to the standard error ouput with an error code different from 0 [#74] +- Documentation updated [#74] + +### Fixed +- JSON empty string colorisation [#72] + ## [1.2.2](https://github.com/ABridoux/scout/tree/1.2.2) (04/07/2020) ### Added diff --git a/Package.resolved b/Package.resolved index b3d6a958..9f9af170 100644 --- a/Package.resolved +++ b/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/ABridoux/lux", "state": { "branch": null, - "revision": "c0b65dceb8e36335874c412c9611fdac021a57af", - "version": "0.3.6" + "revision": "c433264cec4e9c8563d93d2fecb0af65e683f01d", + "version": "0.3.7" } }, { diff --git a/README.md b/README.md index 69eee2a7..987f8f71 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ Install:
+ + +

diff --git a/Resources/scout-logo.png b/Resources/scout-logo.png index 77c53e37..7b069a78 100644 Binary files a/Resources/scout-logo.png and b/Resources/scout-logo.png differ diff --git a/Sources/Scout/Constants/Version.swift b/Sources/Scout/Constants/Version.swift index 1bcf62c2..d3555e83 100644 --- a/Sources/Scout/Constants/Version.swift +++ b/Sources/Scout/Constants/Version.swift @@ -1,3 +1,3 @@ public struct Version { - public static let current = "1.2.2" + public static let current = "1.2.3" } diff --git a/Sources/Scout/Definitions/Path.swift b/Sources/Scout/Definitions/Path.swift index bfe6e8d9..13f716be 100644 --- a/Sources/Scout/Definitions/Path.swift +++ b/Sources/Scout/Definitions/Path.swift @@ -48,15 +48,16 @@ public extension Path { - note: The following separators will not work: "[", "]", "(", ")". When using a special caracter with [regular expression](https://developer.apple.com/documentation/foundation/nsregularexpression#1965589), it is required to quote it with "\\". - */ init(string: String, separator: String = "\\.") throws { var elements = [PathElement]() let splitRegexPattern = #"\(.+\)|[^\#(separator)]+"# let indexRegexPattern = #"(?<=\[)[0-9-]+(?=\])"# - let splitRegex = try NSRegularExpression(pattern: splitRegexPattern, options: []) - let indexRegex = try NSRegularExpression(pattern: indexRegexPattern, options: []) + let squareBracketPattern = #"\[|\]"# + let splitRegex = try NSRegularExpression(pattern: splitRegexPattern) + let indexRegex = try NSRegularExpression(pattern: indexRegexPattern) + let squareBracketRegex = try NSRegularExpression(pattern: squareBracketPattern) let matches = splitRegex.matches(in: string) for match in matches { @@ -94,8 +95,10 @@ public extension Path { guard let index = Int(match[indexMatch.range]) else { throw PathExplorerError.invalidPathElement(match) } elements.append(index) } - } else { + if squareBracketRegex.firstMatch(in: match, range: match.nsRange) != nil { + throw PathExplorerError.invalidPathElement(match) + } elements.append(match) } } diff --git a/Sources/Scout/Definitions/PathExplorerError.swift b/Sources/Scout/Definitions/PathExplorerError.swift index 312f6e40..7c6f6af3 100644 --- a/Sources/Scout/Definitions/PathExplorerError.swift +++ b/Sources/Scout/Definitions/PathExplorerError.swift @@ -21,27 +21,27 @@ public enum PathExplorerError: LocalizedError { switch self { case .invalidData(let type): return "Cannot intialize a \(String(describing: type)) object with the given data" case .invalidValue(let value): return "The key value \(value) is invalid" - case .valueConversionError(let value, let type): return "Unable to convert the value \(value) to \(type)" + case .valueConversionError(let value, let type): return "Unable to convert the value `\(value)` to the type \(type)" case .wrongValueForKey(let value, let element): return "Cannot set `\(value)` to key/index #\(element)# which is a Dictionary or an Array" - case .dictionarySubscript(let path): return "Cannot subscript the key at '\(path.description)' as it is not a Dictionary" + case .dictionarySubscript(let path): return "Cannot subscript the key at '\(path.description)' with a String as it is not a Dictionary" case .subscriptMissingKey(let path, let key, let bestMatch): let bestMatchString: String if let match = bestMatch { - bestMatchString = "Best match found: \(match)" + bestMatchString = "Best match found: #\(match)#" } else { bestMatchString = "No best match found" } return "The key #\(key)# cannot be found in the Dictionary '\(path.description)'. \(bestMatchString)" - case .arraySubscript(let path): return "Cannot subscript the key at '\(path.description)' as is not an Array" + case .arraySubscript(let path): return "Cannot subscript the key at '\(path.description)' with an Integer as is not an Array" case .subscriptWrongIndex(let path, let index, let arrayCount): return "The index #\(index)# is not within the bounds of the Array (0...\(arrayCount - 1)) at '\(path.description)'" case .stringToDataConversionError: return "Unable to convert the input string into data" case .dataToStringConversionError: return "Unable to convert the data to a string" - case .invalidPathElement(let element): return "Invalid path element: \(element)" + case .invalidPathElement(let element): return "Invalid path element: '\(element)'" case .underlyingError(let description): return description } diff --git a/Sources/ScoutCLT/Add/AddCommand.swift b/Sources/ScoutCLT/Add/AddCommand.swift index 8c30329c..5f11b3a5 100644 --- a/Sources/ScoutCLT/Add/AddCommand.swift +++ b/Sources/ScoutCLT/Add/AddCommand.swift @@ -36,9 +36,6 @@ struct AddCommand: ParsableCommand { let streamInput = FileHandle.standardInput.readDataToEndOfFile() try add(from: streamInput) } - } catch let error as PathExplorerError { - print(error.commandLineErrorDescription) - return } } diff --git a/Sources/ScoutCLT/Command.swift b/Sources/ScoutCLT/Command.swift deleted file mode 100644 index e30a27c1..00000000 --- a/Sources/ScoutCLT/Command.swift +++ /dev/null @@ -1,5 +0,0 @@ -import ArgumentParser - -enum Command: String, ExpressibleByArgument { - case read, set, delete, add -} diff --git a/Sources/ScoutCLT/Delete/DeleteCommand.swift b/Sources/ScoutCLT/Delete/DeleteCommand.swift index d561f948..caabdc31 100644 --- a/Sources/ScoutCLT/Delete/DeleteCommand.swift +++ b/Sources/ScoutCLT/Delete/DeleteCommand.swift @@ -43,9 +43,6 @@ struct DeleteCommand: ParsableCommand { let streamInput = FileHandle.standardInput.readDataToEndOfFile() try delete(from: streamInput) } - } catch let error as PathExplorerError { - print(error.commandLineErrorDescription) - return } } diff --git a/Sources/ScoutCLT/Extensions/ArgumentHelp+Extensions.swift b/Sources/ScoutCLT/Extensions/ArgumentHelp+Extensions.swift new file mode 100644 index 00000000..3bf540d5 --- /dev/null +++ b/Sources/ScoutCLT/Extensions/ArgumentHelp+Extensions.swift @@ -0,0 +1,14 @@ +import ArgumentParser + +extension ArgumentHelp { + + static var readingPath: ArgumentHelp { + ArgumentHelp( + "Path in the data where to read the key value", + discussion: """ + A path is a sequence of keys separated with dots to navigate through the data. + Use a dot '.' to subscript a dictionary. For example 'parent_key.child_key'. + Use an integer enclosed by square brakets '[1]' to subscript an array. For example 'first_key.array[0].second_key' + """) + } +} diff --git a/Sources/ScoutCLT/Extensions/Path+Extensions.swift b/Sources/ScoutCLT/Extensions/Path+Extensions.swift index 2bf1d403..680a8440 100644 --- a/Sources/ScoutCLT/Extensions/Path+Extensions.swift +++ b/Sources/ScoutCLT/Extensions/Path+Extensions.swift @@ -1,14 +1,10 @@ import Scout import ArgumentParser +import Foundation extension Path: ExpressibleByArgument { public init?(argument: String) { - do { - self = try Path(string: argument) - } catch { - print(error.localizedDescription) - return nil - } + try? self.init(string: argument) } } diff --git a/Sources/ScoutCLT/Extensions/PathExplorerError+Extensions.swift b/Sources/ScoutCLT/Extensions/PathExplorerError+Extensions.swift deleted file mode 100644 index 86752286..00000000 --- a/Sources/ScoutCLT/Extensions/PathExplorerError+Extensions.swift +++ /dev/null @@ -1,38 +0,0 @@ -import Scout - -extension PathExplorerError { - - var commandLineErrorDescription: String { - var description = "Error".error + ": " - - switch self { - case .invalidData(let type): description += "Cannot intialize a \(String(describing: type).bold) object with the given data" - case .invalidValue(let value): description += "The key value \(String(describing: value).bold) is invalid" - case .valueConversionError(let value, let type): description += "Unable to convert the value \(String(describing: value).bold) to \(String(describing: type).bold)" - case .wrongValueForKey(let value, let element): description += "Cannot set \(String(describing: value).bold) to key/index \(String(describing: element).bold) which is a Dictionary or an Array" - - case .dictionarySubscript(let path): description += "Cannot subscript the key at '\(path.description.bold)' as it is not a Dictionary" - case .subscriptMissingKey(let path, let key, let bestMatch): - let bestMatchString: String - - if let match = bestMatch { - bestMatchString = "Best match found: \(match.bold)" - } else { - bestMatchString = "No best match found" - } - - description += "The key \(key.bold) cannot be found in the Dictionary '\(path.description.bold)'. \(bestMatchString)" - - case .arraySubscript(let path): description += "Cannot subscript the key at '\(path.description.bold)' as is not an Array" - case .subscriptWrongIndex(let path, let index, let arrayCount): description += "The index \(String(index).bold) is not within the bounds of the Array (0...\(arrayCount - 1)) at '\(path.description)'" - - case .stringToDataConversionError: description += "Unable to convert the input string into data" - case .dataToStringConversionError: description += "Unable to convert the data to a string" - case .invalidPathElement(let element): description += "Invalid path element: \(String(describing: element).bold)" - - case .underlyingError(let message): description += message - } - - return description - } -} diff --git a/Sources/ScoutCLT/Extensions/String+Extensions.swift b/Sources/ScoutCLT/Extensions/String+Extensions.swift index d8f945fd..6c45b5ef 100644 --- a/Sources/ScoutCLT/Extensions/String+Extensions.swift +++ b/Sources/ScoutCLT/Extensions/String+Extensions.swift @@ -15,10 +15,11 @@ extension String { static var prefix: String { "\u{001B}[" } static var colorReset: String { "\(Self.prefix)39m" } static var reset: String { "\(Self.prefix)0m" } + var mainColor: String { colored(with: 88) } var bold: String { "\(Self.prefix)1;39m\(self)\(Self.prefix)22m" } var error: String { "\(Self.colorPrefix(91))\(self)\(Self.colorReset)"} static func colorPrefix(_ code: Int) -> String { "\(prefix)38;5;\(code)m" } - + func colored(with code: Int) -> String { "\(Self.colorPrefix(code))\(self)\(Self.reset)" } } diff --git a/Sources/ScoutCLT/Main/DocCommand.swift b/Sources/ScoutCLT/Main/DocCommand.swift index 1e4a7ba0..880965f9 100644 --- a/Sources/ScoutCLT/Main/DocCommand.swift +++ b/Sources/ScoutCLT/Main/DocCommand.swift @@ -1,115 +1,105 @@ import ArgumentParser import Lux -private let jsonInjector = JSONInjector(type: .terminal) -private let zshInjector = ZshInjector(type: .terminal) - -private let jsonExample = -""" -{ - "people": { - "Tom": { - "height": 175, - "age": 68, - "hobbies": [ - "cooking", - "guitar" - ] - }, - "Arnaud": { - "height": 180, - "age": 23, - "hobbies": [ - "video games", - "party", - "tennis" - ] +struct HomeDocumentation: Documentation { + + private static let jsonInjector = JSONInjector(type: .terminal) + private static let zshInjector = ZshInjector(type: .terminal) + + private static let jsonExample = + """ + { + "people": { + "Tom": { + "height": 175, + "age": 68, + "hobbies": [ + "cooking", + "guitar" + ] + }, + "Arnaud": { + "height": 180, + "age": 23, + "hobbies": [ + "video games", + "party", + "tennis" + ] + } + } } - } + """ + + private static let readExamples = [(#"`scout "people.Tom.hobbies[0]"`"#, #"will output "cooking""#), + (#"`scout "people.Arnaud.height"`"#, #"will output "180""#), + (#"`scout "people.Tom.hobbies[-1]"`"#, #"will output last Tom hobbies: "guitar""#), + (#"`scout "people.Tom`"#, #"will output Tom dictionary"#)] + + private static let setExamples = [(#"`scout set "people.Tom.hobbies[0]=basket"`"#, #"will change Tom first hobby from "cooking" to "basket""#), + (#"`scout set "people.Arnaud.height=160"`"#, #"will change Arnaud's height from 180 to 160"#), + (#"`scout set "people.Tom.age=#years#"`"#, #"will change Tom age key name from #age# to #years#"#), + (#"`scout set "people.Tom.hobbies[-1]"="playing music""#, #"will change Tom last hobby from "guitar" to "playing music""#)] + + private static let deleteExamples = [(#"`scout delete "people.Tom.height"`"#, #"will delete Tom height"#), + (#"`scout delete "people.Tom.hobbies[0]"`"#, #"will delete Tom first hobby"#), + (#"`scout delete "people.Tom.hobbies[-1]"`"#, #"will delete Tom last hobby"#)] + + private static let addExamples = [(#"`scout add "people.Franklin.height=165"`"#, #"will create a new dictionary Franklin and add a height key into it with the value 165"#), + (#"`scout add "people.Tom.hobbies[-1]"="Playing music"`"#, #"will add the hobby "Playing music" to Tom hobbies at the end of the array"#), + (#"`scout add "people.Arnaud.hobbies[1]=reading"`"#, #"will insert the hobby "reading" to Arnaud hobbies between the hobby "video games" and "party""#), + (#"`scout add "people.Arnaud.hobbies[-1]=surf"`"#, #"will add the hobby "surf" to Arnaud hobbies at the end of the array"#), + (#"`scout add "people.Franklin.hobbies[0]=football"`"#, #"will create a new dictionary Franklin, add a hobbies array into it, and insert the value "football" in the array"#)] + + static let text = + """ + \u{001B}[38;5;88m + ______ ______ ___ _____ _____ _________ + .' ____ \\ .' ___ | .' `.|_ _||_ _|| _ _ | + | (___ \\_|/ .' \\_|/ .-. \\ | | | | |_/ | | \\_| + _.____`. | | | | | | | ' ' | | | + | \\____) |\\ `.___.'\\\\ `-' / \\ \\__/ / _| |_ + \\______.' `.____ .' `.___.' `.__.' |_____| + + \u{001B}[0;0m + + Here is an overview of scout subcommands: \(Command.documentationDescription). + To get more insights for a specific command, please type `scout doc \("[command]".mainColor)`. + + To indicate what value to target, a reading path should be indicated. + \(ArgumentHelp.readingPath.discussion) + + You can find more examples here: \("https://github.com/ABridoux/scout/wiki/%5B20%5D-Usage-examples:-command-line".mainColor) + + Notes + ===== + - An index is indicated between squared brackets, like this [5] + - When reading a value, the output is always a string + + Given the following Json (as input stream or file) + + \(jsonInjector.inject(in: jsonExample)) + + Examples + ======== + + Reading + ------- + \(examplesText(from: readExamples)) + + Setting + ------- + \(examplesText(from: setExamples)) + + Deleting + -------- + \(examplesText(from: deleteExamples)) + + Adding + ------ + \(examplesText(from: addExamples)) + """ } -""" - -private let readExamples = [#"`scout "people.Tom.hobbies[0]"`"#, - #"`scout "people.Arnaud.height"`"#, - #"`scout "people.Tom.hobbies[-1]"`"#, - #"`scout "people.Tom`"#] - -private let setExamples = [#"`scout set "people.Tom.hobbies[0]=basket"`"#, - #"`scout set "people.Arnaud.height=160"`"#, - #"`scout set "people.Tom.age=#years#"`"#, - #"`scout set "people.Tom.hobbies[-1]"="playing music""#] - -private let deleteExamples = [#"`scout delete "people.Tom.height"`"#, - #"`scout delete "people.Tom.hobbies[0]"`"#, - #"`scout delete "people.Tom.hobbies[-1]"`"#] - -private let addExamples = [#"`scout add "people.Franklin.height=165"`"#, - #"`scout add "people.Tom.hobbies[-1]"="Playing music"`"#, - #"`scout add "people.Arnaud.hobbies[1]=reading"`"#, - #"`scout add "people.Arnaud.hobbies[-1]=surf"`"#, - #"`scout add "people.Franklin.hobbies[0]=football"`"#] - -private let documentation = -""" -\u{001B}[38;5;88m - ______ ______ ___ _____ _____ _________ - .' ____ \\ .' ___ | .' `.|_ _||_ _|| _ _ | - | (___ \\_|/ .' \\_|/ .-. \\ | | | | |_/ | | \\_| - _.____`. | | | | | | | ' ' | | | - | \\____) |\\ `.___.'\\\\ `-' / \\ \\__/ / _| |_ - \\______.' `.____ .' `.___.' `.__.' |_____| - -\u{001B}[0;0m - -Here is an overview of scout subcommands: read, set, delete and add. -To get more insights for a specifi command, please type `scout doc [command]`. - -To indicate what value to target, a path should be indicated. A path is a serie of key names or indexes separated by '.' to target one value. -It looks like this "firt_key.second_key[second_index].third_key". - -You can find more examples here: \u{001B}[38;5;88mhttps://github.com/ABridoux/scout/blob/master/Playground/Commands.md\u{001B}[0;0m - -Notes -===== -- An index is indicated between squared brackets, like this [5] -- When reading a value, the output is always a string - -Given the following Json (as input stream or file) - -\(jsonInjector.inject(in: jsonExample)) - -Examples -======== - -Reading -------- -\(zshInjector.inject(in: readExamples[0])) will output "cooking" -\(zshInjector.inject(in: readExamples[1])) will output "180" -\(zshInjector.inject(in: readExamples[2])) will output last Tom hobbies: "guitar" -\(zshInjector.inject(in: readExamples[3])) will output Tom dictionary - -Setting -------- -\(zshInjector.inject(in: setExamples[0])) will change Tom first hobby from "cooking" to "basket" -\(zshInjector.inject(in: setExamples[1])) will change Arnaud's height from 180 to 160 -\(zshInjector.inject(in: setExamples[2])) will change Tom age key name from #age# to #years# -\(zshInjector.inject(in: setExamples[3])) will change Tom last hobby from "guitar" to "playing music" - -Deleting --------- -\(zshInjector.inject(in: deleteExamples[0])) will delete Tom height -\(zshInjector.inject(in: deleteExamples[1])) will delete Tom first hobby -\(zshInjector.inject(in: deleteExamples[2])) will delete Tom last hobby - -Adding ------- -\(zshInjector.inject(in: addExamples[0])) will create a new dictionary Franklin and add a height key into it with the value 165 -\(zshInjector.inject(in: addExamples[1])) will add the hobby "Playing music" to Tom hobbies at the end of the array -\(zshInjector.inject(in: addExamples[2])) will insert the hobby "reading" to Arnaud hobbies between the hobby "video games" and "party" -\(zshInjector.inject(in: addExamples[3])) will add the hobby "surf" to Arnaud hobbies at the end of the array -\(zshInjector.inject(in: addExamples[4])) will create a new dictionary Franklin, add a hobbies array into it, and insert the value "football" in the array - -""" struct DocCommand: ParsableCommand { static let configuration = CommandConfiguration( @@ -128,7 +118,7 @@ static let configuration = CommandConfiguration( case .add: print(AddDocumentation.text) } } else { - print(documentation) + print(HomeDocumentation.text) } } } diff --git a/Sources/ScoutCLT/Models/Command.swift b/Sources/ScoutCLT/Models/Command.swift new file mode 100644 index 00000000..7d505df9 --- /dev/null +++ b/Sources/ScoutCLT/Models/Command.swift @@ -0,0 +1,9 @@ +import ArgumentParser + +enum Command: String, ExpressibleByArgument { + case read, set, delete, add + + static var documentationDescription: String { + "\(Self.read.rawValue.mainColor), \(Self.set.rawValue.mainColor), \(Self.delete.rawValue.mainColor) and \(Self.add.rawValue.mainColor)" + } +} diff --git a/Sources/ScoutCLT/Documentation.swift b/Sources/ScoutCLT/Models/Documentation.swift similarity index 100% rename from Sources/ScoutCLT/Documentation.swift rename to Sources/ScoutCLT/Models/Documentation.swift diff --git a/Sources/ScoutCLT/PathAndValue.swift b/Sources/ScoutCLT/Models/PathAndValue.swift similarity index 97% rename from Sources/ScoutCLT/PathAndValue.swift rename to Sources/ScoutCLT/Models/PathAndValue.swift index 64cafc26..e0c3b2e7 100644 --- a/Sources/ScoutCLT/PathAndValue.swift +++ b/Sources/ScoutCLT/Models/PathAndValue.swift @@ -3,7 +3,7 @@ import Scout private let abstract = """ -Let you specify a reading path with an associated value. Like this: `FirstKey.SecondKey[Index].ThirdKey"=value` +Let you specify a reading path with an associated value. Like this: "FirstKey.SecondKey[Index].ThirdKey=value" or `"FirstKey[Index]"="Text value with spaces"` """ diff --git a/Sources/ScoutCLT/RuntimeError.swift b/Sources/ScoutCLT/Models/RuntimeError.swift similarity index 100% rename from Sources/ScoutCLT/RuntimeError.swift rename to Sources/ScoutCLT/Models/RuntimeError.swift diff --git a/Sources/ScoutCLT/ValueType.swift b/Sources/ScoutCLT/Models/ValueType.swift similarity index 100% rename from Sources/ScoutCLT/ValueType.swift rename to Sources/ScoutCLT/Models/ValueType.swift diff --git a/Sources/ScoutCLT/Read/ReadCommand.swift b/Sources/ScoutCLT/Read/ReadCommand.swift index ddfd1062..482daf4f 100644 --- a/Sources/ScoutCLT/Read/ReadCommand.swift +++ b/Sources/ScoutCLT/Read/ReadCommand.swift @@ -14,7 +14,7 @@ struct ReadCommand: ParsableCommand { // MARK: - Properties - @Argument(help: "Path in the data where to read the key value") + @Argument(help: .readingPath) var readingPath: Path? @Option(name: [.short, .customLong("input")], help: "A file path from which to read the data") @@ -49,10 +49,6 @@ struct ReadCommand: ParsableCommand { let output = color ? injector.inject(in: value) : value print(output) - - } catch let error as PathExplorerError { - print(error.commandLineErrorDescription) - return } } diff --git a/Sources/ScoutCLT/Read/ReadDocumentation.swift b/Sources/ScoutCLT/Read/ReadDocumentation.swift index b9d9ca58..17ab75dd 100644 --- a/Sources/ScoutCLT/Read/ReadDocumentation.swift +++ b/Sources/ScoutCLT/Read/ReadDocumentation.swift @@ -30,10 +30,10 @@ struct ReadDocumentation: Documentation { } """ - private static let examples = [(#"`scout "people.Tom.hobbies[0]"`"#, #"will output Tom first hobby "cooking")"#), + private static let examples = [(#"`scout "people.Tom.hobbies[0]"`"#, #"will output Tom first hobby "cooking""#), (#"`scout "people.Arnaud.height"`"#, #"will output Arnaud's height "180""#), (#"`scout "people.Tom.hobbies[-1]"`"#, #"will output Tom last hobby: "guitar""#), - (#"`scout "people.Tom`"#, #"will output Tom dictionary"#)] + (#"`scout "people.Tom"`"#, #"will output Tom dictionary"#)] static let text = """ diff --git a/Sources/ScoutCLT/Set/SetCommand.swift b/Sources/ScoutCLT/Set/SetCommand.swift index ab56e789..4273035f 100644 --- a/Sources/ScoutCLT/Set/SetCommand.swift +++ b/Sources/ScoutCLT/Set/SetCommand.swift @@ -36,9 +36,6 @@ struct SetCommand: ParsableCommand { let streamInput = FileHandle.standardInput.readDataToEndOfFile() try set(from: streamInput) } - } catch let error as PathExplorerError { - print(error.commandLineErrorDescription) - return } } diff --git a/Sources/ScoutCLT/VersionCommand.swift b/Sources/ScoutCLT/Version/VersionCommand.swift similarity index 100% rename from Sources/ScoutCLT/VersionCommand.swift rename to Sources/ScoutCLT/Version/VersionCommand.swift