Content AND Presentation

2020-06-01 Node modules working as command-line scripts

Recently, I wanted to run one Node.JS CLI script from another. Of course, being in a hurry and KISS and whatnot, I decided to just use child_process.execFileSync with node as the first argument, but this is of course grossly inefficient. What if I could write a module usable both from the command line and other code?

Well, it turns out that not only is this doable, but actually easy and robust. (Anyone working with JavaScript for more than a week will appreciate the last part. ;-) )

First things first: to determine if the code is ran as a standalone script (using the Node binary) or required/imported, it is enough to test if require.main === module. (I first learned this from this Petr Stodulka’s post, and – since that post was pretty old – confirmed this with the current documentation. Notice that Stodulka uses ==, which works, but I’d rather use ===.)

Now the example was in CoffeeScript instead of plain JS, and used module.exports and require (which are perfectly fine, but a bit old-fashioned), so I decided to experiment a bit with the newer export / import syntax. Unfortunately, this seems harder than I thought – I don’t even know if it’s possible. I think perusing the docs might reveal an answer to this question, but I’m afraid it’s negative. Since I am perfectly ok with using module.exports and require for my needs here, I’ll go with it.

So, here’s my take on this. Unlike Stodulka, I am not going to use yargs (which I like nevertheless) here for the sake of simplicity. My module (let’s call it show_args.js) looks like this:

#!/usr/bin/node

function show_args(...args) {
	console.log(`Arguments were ${args}.`);
}

if (require.main === module) {
	show_args(process.argv);
} else {
	module.exports = show_args;
}

I define the show_args function which does nothing interesting besides printing its arguments. Also, I include the shebang so that the file can be executed directly (this is not needed of you intend to run it via node show_args.js). Finall, I run the show_args function with the command-line parameters if it was run as a standalone script, and export that function otherwise.

Now you can say ./show_args.js 1 2 3 (see what happens!), but you can also use this as a module in another Node.JS script or even a web app, like this:

const show_args = require('./show_args.js');
show_args(1, 2, 3);

Happy scripting!

CategoryEnglish, CategoryBlog, CategoryJavaScript

Comments on this page

2020-05-24 Two parameters and at least one required in yargs

I happen to write shell scripts in Node.JS quite often. They usually consume some kind of command-line arguments, and my library of choice to parse them is yargs.

Recently, I had a situation where there were two parameters and it was required that one of them is given. A bit surprisingly, yargs1 does not seem to have an option requiredAlternative or something that says “of the following two parameters, at least one must be given” (it has a conflicts method and option, either of which can be used to say e.g. “of these two parameters, at most one may be given”, though).

Happily, there is a simple way to enforce such a requirement due to the quite general “check” method. With it, you can enforce various non-trivial restrictions on the arguments, more complicated than “A is required” or “A conflicts with B​” Here is how you can use it.

const argv = require('yargs')
	.option('a', {
		demandOption: false,
	})
	.option('b', {
		demandOption: false,
	})
	.conflicts('a', 'b')
	.check((argv) => {
		if (!argv.a && !argv.b) {
			throw new Error('You must supply either --a or --b');
		} else {
			return true;
		}
	})
	.argv;

console.log(argv.a ? '--a supplied' : '--b supplied');

Note that the function supplied as the argument to check gets a second argument – an object whose keys are the option names and values are arrays of all possible aliases of each option. I have no idea what it could be used for, but there it is.

CategoryEnglish, CategoryBlog, CategoryJavaScript

Comments on this page

2020-05-18 entr, a wrapper around inotify

Shortly after my post from last year describing how I use inotifywait to start programs on file change, one of the readers emailed me about an utility called entr. It is an extremely simple-to-use tool which just gets the filelist to watch on stdin and a command to execute when any of the files changes as CLI arguments – and that’s pretty much it. (That does not imply it is simplistic – according to its website, it performs some non-trivial stuff under the hood.) Thanks!

CategoryEnglish, CategoryBlog

Comments on this page

More...

CategoryEnglish, CategoryBlog