diff --git a/Sources/CLI/CLI.swift b/Sources/CLI/CLI.swift index d65b231..668048f 100644 --- a/Sources/CLI/CLI.swift +++ b/Sources/CLI/CLI.swift @@ -7,7 +7,7 @@ struct Tool: ParsableCommand { static var configuration = CommandConfiguration( commandName: "dotenvy-tool", abstract: "Tool for working with dotenv files", - subcommands: [Check.self] + subcommands: [Check.self, JSON.self] ) } @@ -43,6 +43,49 @@ struct Check: ParsableCommand { } } +struct JSON: ParsableCommand { + static var configuration + = CommandConfiguration( + abstract: "Convert input to JSON.", + discussion: """ + The input is converted to a JSON object. + + In case of a syntax error, the error is printed to standard error and the + command exits with failure code \(ExitCode.failure.rawValue). + + If there are no problems reading the input, the JSON value is printed to + standard output and the command exits with \(ExitCode.success.rawValue). + """ + ) + + @Argument(help: "Input file. Standard input is used if omitted") + var file: FileURL? + + @Flag(help: "Pretty print JSON") + var pretty: Bool = false + + func validate() throws { + _ = try self.file?.url.checkResourceIsReachable() + } + + func run() throws { + let string = try readInput(self.file) + do { + let values = try DotEnvironment.parse(string: string) + let json = try JSONSerialization.data( + withJSONObject: values, + options: self.pretty ? [.prettyPrinted, .sortedKeys] : [] + ) + FileHandle.standardOutput.write(json) + FileHandle.standardOutput.write(Data("\n".utf8)) + } catch let error as ParseErrorWithLocation { + FileHandle.standardError.write(Data(error.formatError(source: string).utf8)) + FileHandle.standardError.write(Data("\n".utf8)) + throw ExitCode.failure + } + } +} + struct FileURL: ExpressibleByArgument { var url: URL