Skip to content

Commit

Permalink
fix(cli): CLI argument handling and defaults
Browse files Browse the repository at this point in the history
BREAKING CHANGE: No `--baseDir` and `--outDir` default values anymore. Asks for explicit values.
BREAKING CHANGE: Now stops if `--baseDir` and `--outDir` resolve to same directory to prevent overriding sources. Can be ignored with `--force` flag.
BREAKING CHANGE: CLI options now take precedence over config file options. CLI opts used together with config file opts caused config file opts to become effective.
  • Loading branch information
about-code committed Sep 28, 2019
1 parent b57231b commit c55cee0
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 29 deletions.
83 changes: 57 additions & 26 deletions bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const path = require("path");
const proc = require("process");
const glossarify = require("../lib/glossarify");
const confSchema = require("../conf.schema.json").properties;
const messages = require("../lib/messages");

const CWD = proc.cwd();
const {version} = require("../package.json");
Expand All @@ -16,35 +17,25 @@ console.log(
└──────────────────────────┘
`)

// CLI
const parameters = Object.assign(
const opts = Object.assign(
{
"config": { type: "string", alias: "c", default: "" , description: "Path to config file, e.g. './glossarify-md.conf.json'."},
"help": { type: "boolean", alias: "h", default: false, description: "Show this help."}
},
confSchema
);
const cliOpts = buildOpts(parameters);
const args = minimist(proc.argv.slice(2), cliOpts);

if (args.help || proc.argv.length === 2) {
console.log("Options:\n");
console.log(
Object
.keys(parameters)
.filter(key => key !== "dev")
.map(key => {
const {alias, type, description, default:_default} = parameters[key];
return `--${key}, --${alias} (${type})\n ${description}\n Default: ${JSON.stringify(_default)}\n\n`;
})
.join("")
);
process.exit(0);
}

// Read file opts
// CLI
const defaults = minimist([], buildOpts(opts));
const cliArgs = minimist(proc.argv.slice(2));
let conf = {};
const confPath = args.config;

// --help (or no args at all)
if (cliArgs.help || proc.argv.length === 2) {
printHelp(opts);
}
// --config
const confPath = cliArgs.config;
let confDir = CWD;
if (confPath) {
try {
Expand All @@ -56,13 +47,53 @@ if (confPath) {
}
}

// Merge CLI opts with file opts
conf = Object.assign(args, conf);
// command-line arguments must take precedence over config file and defaults
conf = Object.assign(defaults, conf, cliArgs);
conf.baseDir = path.resolve(confDir, conf.baseDir);
conf.outDir = path.resolve(conf.baseDir, conf.outDir);
console.log(`-> Reading from: ${conf.baseDir}`);
console.log(`-> Writing to: ${conf.outDir}
`);
validateConfig(conf);

// Run
glossarify.glossarify(conf);

// Helpers
function printHelp(parameters) {
console.log("Options:\n");
console.log(
Object
.keys(parameters)
.filter(key => key !== "dev")
.sort((a, b) => a.localeCompare(b, "en"))
.map(key => {
const {alias, type, description, default:_default} = parameters[key];
return `--${key}${alias ? ', --' + alias : ''} (${type})\n ${description}\n Default: ${JSON.stringify(_default)}\n\n`;
})
.join("")
);
process.exit(0);
}

function validateConfig(conf) {

if (conf.baseDir === "") {
console.log(messages.NO_BASEDIR);
console.log('ABORTED.\n');
proc.exit(0);
}

if (conf.outDir === "") {
console.log(messages.NO_OUTDIR);
console.log('ABORTED.\n');
proc.exit(0);
}

console.log(`☛ Reading from: ${conf.baseDir}`);
console.log(`☛ Writing to: ${conf.outDir}
`);

if (conf.outDir === conf.baseDir && !conf.force) {
console.log(messages.OUTDIR_IS_BASEDIR)
console.log('ABORTED.\n');
proc.exit(0);
}
}
11 changes: 8 additions & 3 deletions conf.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
"description": "Path to directory where to search for the glossary file and markdown files. All paths in a config file will be relative to *baseDir*. *baseDir* itself is relative to the location of the config file or the current working directory when provided via command line.",
"type": "string",
"alias": "d",
"default": "./src"
"default": ""
},
"baseUrl": {
"description": "The base url to use when creating absolute links to glossary.",
"type": "string",
"format": "url",
"alias": "b",
"default": "http://127.0.0.1/"
"default": "http://127.0.0.1"
},
"excludeFiles": {
"description": "An array of files or file name patterns that should not be included in any processing.",
Expand All @@ -25,6 +25,11 @@
"alias": "e",
"default": ["node_modules", ".git"]
},
"force": {
"description": "Choose true, only if you know the consequences.",
"type": "boolean",
"default": false
},
"glossaries": {
"description": "An array of glossaries. Allows for different kinds of glossaries and definitions.",
"type": "array",
Expand Down Expand Up @@ -74,7 +79,7 @@
"description": "Path to directory where to write processed files to.",
"type": "string",
"alias": "o",
"default": "./target"
"default": ""
},
"dev": {
"descriptions": "Options for testing and debugging",
Expand Down
24 changes: 24 additions & 0 deletions lib/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const NO_BASEDIR =
`✗ Missing argument --baseDir.
Please provide via command line or config file.
See --help for details.
`;

const NO_OUTDIR =
`✗ Missing argument --outDir.
Please provide via command line or config file.
See --help for details.
`;

const OUTDIR_IS_BASEDIR =
`⚠ Warning: --baseDir and --outDir resolve to the same directory.
Such a config is going to overwrite input files in --baseDir.
Choose a different --outDir or change config provided via --config.
Use --force if you want to proceed with current settings.
See --help for details.
`
module.exports = {
NO_BASEDIR,
NO_OUTDIR,
OUTDIR_IS_BASEDIR
}

0 comments on commit c55cee0

Please sign in to comment.