diff --git a/README.md b/README.md index 392b4e8..8a32825 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,9 @@ standard-clj fix ## or pass a config file explicitly using the --config argument standard-clj list --config /home/user1/my-project/my-standard-cfg.json + +## pipe code directly to the fix command using "-" +echo '(ns my.company.core (:require [clojure.string :as str]))' | standard-clj fix - ``` #### `list` command @@ -137,6 +140,17 @@ Returns exit code 0 if all files have been formatted, 1 otherwise. standard-clj fix src/ test/ deps.edn ``` +#### `fix -` command (stdin / stdout) + +Use `standard-clj fix -` to pipe code directly via stdin. + +Prints the formatted code to stdout with error code 0 if successful. Prints an +error message to stderr with error code 1 otherwise. + +```sh +echo '(ns my.company.core (:require [clojure.string :as str]))' | standard-clj fix - +``` + #### Which files will be formatted? `standard-clj` accepts several ways to know which files to format: diff --git a/cli.mjs b/cli.mjs index bd2e851..f179cd9 100644 --- a/cli.mjs +++ b/cli.mjs @@ -377,7 +377,8 @@ function processCheckCmd (argv) { } } -function processFixCmd (argv) { +// this is the fix command when not reading input from stdin +function processFixCmdNotStdin (argv) { setLogLevel(argv['log-level']) printProgramInfo({ command: 'fix' }) @@ -420,6 +421,38 @@ function processFixCmd (argv) { } } +// fix command when reading input from stdin +async function processFixCmdStdin (argv) { + const stdinStr = await readStream(process.stdin) + + if (!isString(stdinStr) || stdinStr === '') { + exitSad('Nothing found on stdin. Please pipe some Clojure code to stdin when using "standard-clj fix -"') + } else { + let formatResult = null + try { + formatResult = standardClj.format(stdinStr) + } catch (e) {} + + if (formatResult && formatResult.status === 'success') { + console.log(formatResult.out) + exitHappy() + } else if (formatResult && formatResult.status === 'error' && isString(formatResult.reason)) { + exitSad('Failed to format code: ' + formatResult.reason) + } else { + exitSad('Failed to format your code due to unknown error with the format() function. Please help the standard-clj project by opening an issue to report this 🙏') + } + } +} + +function processFixCmd (argv) { + const lastArg = getLastItemInArray(argv._) + if (lastArg === '-') { + processFixCmdStdin(argv) + } else { + processFixCmdNotStdin(argv) + } +} + function processListCmd (argv) { const filesSet = getFilesFromArgv(argv, 'list') const sortedFiles = setToArray(filesSet).sort() @@ -501,6 +534,16 @@ function setToArray (s) { return Array.from(s) } +// returns the last item in an Array, or null if the Array is empty +function getLastItemInArray (a) { + const size = a.length + if (size === 0) { + return null + } else { + return a[size - 1] + } +} + // some older versions of node.js do not have Set.difference function setDifference (setA, setB) { if (typeof Set.prototype.difference === 'function') { @@ -548,3 +591,10 @@ function fileStr (numFiles) { if (numFiles === 1) return 'file' else return 'files' } + +// https://stackoverflow.com/a/54565854 +async function readStream (stream) { + const chunks = [] + for await (const chunk of stream) { chunks.push(chunk) } + return Buffer.concat(chunks).toString('utf8') +}