Short answer:
You're not overlooking something obvious. It's rather a case of the feature that you want simply doesn't exist.
Unfortunately zprint-clj does not provide an option to recursively process .clj
files in a bundle of nested folders. It only accepts one input file per usage.
Perhaps you should post a request for this feature to be added in the projects GitHub repo here.
Meanwhile, to meet your requirement you could consider creating a custom node script which utilizes zprint-cli
. This script can then be invoked via your npm script
.
Long answer with solution:
The following demonstrates a solution to fulfill your requirement.
1. Additional packages
Firstly you'll need to cd
to your project directory and install some additional packages locally via npm (Note: we'll also include references to these packages in the devDependencies
section of package.json
):
Install cli-glob by running:
npm i -D cli-glob
Next, install shelljs by running:
npm i -D shelljs
And, if you haven't got it installed locally already, install zprint-clj by running:
npm i -D zprint-clj
2. Custom node script
Next create a custom node script as follows. Let's name the file recursive-zprint.js
and save it to a hidden directory named .scripts
in the root of your project folder.
project
├─── .scripts
│ └─── recursive-zprint.js
├─── node_modules
└─── ...
recursive-zprint.js
const path = require('path');
const readline = require('readline');
const shelljs = require('shelljs');
const TICK = process.platform === 'win32' ? '√' : '✔';
var outputDir = '';
var verbose = false;
// Setup interface to read glob paths piped to stdin.
const rl = readline.createInterface({
input: process.stdin,
output: null,
terminal: false
});
// Read each line from process.stdin
// (i.e. the filepath for each .clj found via the glob pattern)
rl.on('line', function (filePath) {
formatData(filePath);
});
// Handle the optional `-o` argument for the output dir.
if (process.argv.indexOf('-o') !== -1) {
outputDir = process.argv[process.argv.indexOf('-o') + 1];
}
// Handle the optional `-v` argument for verbose logging.
if (process.argv.indexOf('-v') !== -1) {
verbose = true;
}
/**
* Gets the path to node_modules/.bin executable.
* @param {string} command - The executable name
* @returns {string} The path to the executable.
*/
function getBin(command) {
return path.join('node_modules', '.bin', command);
}
/**
* Obtains the destination path for where the formated file should be saved.
* Creates directories, and executes the zprint command . If the `-o` argument
* is not specified via the npm-script the original file is overwritten.
*
* @param {String} srcPath - The path to the source file.
*/
function formatData(srcPath) {
const destPath = getDestPath(srcPath);
makeDirectory(path.dirname(destPath));
shelljs.exec(getBin('zprint-clj') + ' -i ' + srcPath + ' -o ' + destPath);
// Log formatted filepath to console.
if (verbose) {
shelljs.echo('\x1b[32m%s\x1b[0m', TICK, destPath);
}
}
/**
* Obtains destination path for where to save the formatted file. Joins the
* source path, excluding the root directory, with the given output path.
*
* @param {String} srcPath - The path to the source file.
* @return {String} - The destination file path.
*/
function getDestPath(srcPath) {
if (outputDir) {
const parts = srcPath.split(path.sep);
parts.shift();
return path.join(outputDir, parts.join(path.sep));
}
return srcPath;
}
/**
* Create a new directory and intermediate directories if necessary.
* @param {String} dirPath - The path for the directory.
*/
function makeDirectory(dirPath) {
if (!shelljs.test('-d', dirPath)) {
shelljs.mkdir('-p', dirPath);
}
}
3. Configuring npm-scripts
Configure your npm-script as follows. Lets name the script zprint
:
Overwriting the original files...`
{
...
"scripts": {
"zprint": "glob \"src/**/*.clj\" | node .scripts/recursive-zprint"
},
...
}
Note the following:
The script above utilizes cli-glob
to obtain the path to each .clj
file stored in the src
directory many levels deep. You'll need to replace the \"src/**/*.clj\"
part with a glob pattern suitable for your project.
The list of files found by the glob pattern are then piped to the custom node script (i.e. recursive-zprint.js
).
All original source .clj
using this configuration will be overwritten with the formatted data.
Avoid overwriting the original files...
To avoid overwriting the original .clj
files recursive-zprint.js
allows an optional -o
argument to be passed via the script that specified the output directory.
{
...
"scripts": {
"zprint": "glob \"src/**/*.clj\" | node .scripts/recursive-zprint -o \"path/to/output\""
},
...
}
Note the following:
This example configuration includes the additonal -o
argument followed by the path to where the formatted files will be saved.
If you're going to use the -o
argument you'll again need to replace the \"path/to/output\"
part with a suitable output path for your project.
4. Source directory vs resultant directory
Given the last npm script configuration shown (the one which utilizes the -o
argument). Lets assume we have a src
directory with files as follows:
project
├─── src
│ ├─── a.clj
│ ├─── x
│ │ ├─── b.clj
│ │ └─── y
│ │ └─── c.clj
│ └─── d.clj
└─── ...
Afer running npm run zprint
, via your CLI, the resultant output will be as follows (Note the original source sub directories are preserved in the resultant output):
project
├─── path
│ └─── to
│ └─── output
│ ├─── a.clj
│ ├─── x
│ │ ├─── b.clj
│ │ └─── y
│ │ └─── c.clj
│ └─── d.clj
├─── src
│ └─── ... (same as before)
└─── ...
5. Verbose logging
If you want to log to the console the path of each file when it has been formatted successfully you can add the -v
optional argument too. For example:
{
...
"scripts": {
"zprint": "glob \"src/**/*.clj\" | node .scripts/recursive-zprint -v -o \"path/to/output\""
},
...
}