cmdsettings
v1.0.5
Published
Allows for saving and loading options of Commander to and from setting files
Downloads
17
Readme
cmdsettings
Allows for saving and loading options of Commander to and from setting files
General Usage
This package is an extension for the Commander framework to allow for saving and loading of options to and from files. Instead of defining options directly, like
program
.option('-v, --verbose', 'Printout more', false)
.option('--opt1 <string>', 'help1', 'def1')
.option('--opt2 <file>', 'help2', 'def2');
you can define settings and use them to populate your commands with options, e.g.
const settings = {
verbose: new Setting({ short: "v", name: "verbose", help: "Printout more", def: false, settings: false }),
opt1: new Setting({ name: "opt1", help: "help1", def: "def1", }),
opt2: new Setting({ name: "opt2", type: "file", help: "help2", def: "def2", }),
};
program
.addOption(settings.verbose.toOption())
.addOption(settings.opt1.toOption())
.addOption(settings.opt2.toOption());
This looks like more work by first glance. But you get some benefits.
You can load the settings from a settings file (actually, multiple files), just by calling
await Setting.readSettings(settings, { settingsFolderName: ".mytool" });
This would try to load the file "settings.json" (the default name, maybe changed) in a directory ".mytool" in the current working directory. This would also try to load settings files in parent directories and the home directory of the user (if not already found in one of the parent directories).
So, if you have some options which are similar for a given project or the current user, just defined these options by means of settings in one of these files.
Important: The trick is, that setting values read from a setting file are used as default values for options. This way, the default commander.js behavior is not changed and you can simply use options without caring about the setting file. However, you need to read the settings before setting up the commands! As you may want to use verbosity settings when reading the settings files, you may want to use this pattern:
// manually check args for verbosity information, e.g.
const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
// and setup output functions, e.g.
const verb = (s) => {if (verbose) console.log(s)}
// ...
// read settings before setting up commands
await Setting.readSettings(SETTINGS, {
settingsFolderName: ".mytool", settingsFileName: "settings.json",
log: log, verb: verb, error: error, debug: debug
});
// setup program, e.g.
program.command('mycommand')
.addOption(SETTINGS.someOption.toOption()) // value read from setting file will be used as default
.action(cmdMyCommand);
// and execute
program.parse();
In the command, you can then simply use the option, e.g.
function cmdMyCommand(options) {
const someOption = options.someOption;
}
How do these setting files look like. Well, you can easily provide a command (or option, or however you want to do it) which generates a setting file based on the current values:
program.command("generateSettings").action(async () => {
await Setting.writeSettings(settings, { settingsFolderName: ".mytool" });
});
The generated file is a json file with comments. All values matching the default value are added with line comments. Values which are diffent from the default value are directly set in the settings file. This makes it very easy for users to change the files. This is how the file for the example may look like:
{ /* Settings maybe overwritten by subfolder setting files or command line,
overwrites values in parent settings files. */
"opt1": "actVal1", /* help1 (string, default: "def1") */
// "opt2": "def2", /* help2 (file, default: "def2") */
}
The settings have several mandatory properties:
- name: Name of the setting, used as long option in command line
- help: Help text for the setting
- def: The default value of the setting
Most properties are optional:
- short: Short option in command line
- type: Type of the setting, used to generate help text; if not given, the type of the default value is used to infer the type.
- embedded: boolean; Actual value may be embedded in settings file, e.g. as object or array. This can only be defined for file settings. Instead of the filename, the actual value is written to the settings file.
- settings: boolean; If set to false, the setting is not loaded (or written) from a settings file. This is useful for settings that are only used as command line arguments but using the same mechanism as settings.
If the default value is an array, the settings is assumed to be variadic.
Of course, you can also combine the settings with plain commander options, command etc.
Logging
Since CLI tools often use differnt log levels, you can pass special log functions to read- and writeSettings. These functions mimic the signature of console.log etc., which are also the defaults:
- log -> console.log
- verb -> console.verb
- warn -> console.warn
- error -> console.err
- debug -> console.debug
readSettings
print out debug messages about which folders are examined and verbose messages where setting files are found.
You may want to manually parse args in order to make verbosity configurable in readSettings as well, see above for example.