lib/cli.js
function execute(programArgs) {

    let userConfig = {}, ignore, errorReporter;

    createCliOptions(cli);
    programArgs.length === 2 ? cli.help() : cli.parse(programArgs);

    if (cli.init) {
        return setupDefaultUserConfig();
    }

    try {
        errorReporter = getErrorReporter(cli.reporter);
    } catch (e) {
        process.stderr.write(`[Fatal error] ${e.message}${EOL}`);
        process.exit(errorCodes.INVALID_PARAMS);
    }

    if (cli.soliumrc) {
        /**
         * If cli.config option is NOT specified, then resort to .soliumrc in current dir.
         * Else,
         *   If path is absolute, assign as-it-is.
         *   Else (relative pathing) join path with current dir.
         */
        const soliumrcAbsPath = cli.config ?
            (path.isAbsolute(cli.config) ? cli.config : path.join(CWD, cli.config)) :
            SOLIUMRC_FILENAME_ABSOLUTE;

        try {
            userConfig = require(soliumrcAbsPath);
        } catch (e) {
            // Check if soliumrc file exists. If yes, then the file is in an invalid format.
            if (fs.existsSync(soliumrcAbsPath)) {
                errorReporter.reportFatal(`An invalid ${SOLIUMRC_FILENAME} was provided. ${e.message}`);
            } else {
                if (cli.config) {
                    errorReporter.reportFatal(`${soliumrcAbsPath} does not exist.`);
                } else {
                    errorReporter.reportFatal(`Couldn't find ${SOLIUMRC_FILENAME} in the current directory.`);
                }
            }

            process.exit(errorCodes.NO_SOLIUMRC);
        }
    }

    //if custom rules' file is set, make sure we have its absolute path
    if (
        userConfig ["custom-rules-filename"] &&
        !path.isAbsolute(userConfig ["custom-rules-filename"])
    ) {
        userConfig ["custom-rules-filename"] = path.join(
            CWD, userConfig ["custom-rules-filename"]
        );
    }

    // Pass cli arguments that modify the behaviour of upstream functions.
    userConfig.options = {
        autofix: Boolean(cli.fix),
        autofixDryrun: Boolean(cli.fixDryRun),
        debug: Boolean(cli.debug)
    };

    if (userConfig.options.autofixDryrun) {
        if (userConfig.options.autofix) {
            return errorReporter.reportFatal("Cannot use both --fix and --fix-dry-run");
        }
        if (cli.reporter != "pretty") {
            return errorReporter.reportFatal("Option --fix-dry-run is only supported with pretty reporter");
        }
    }

    userConfig.plugins = userConfig.plugins || [];
    userConfig.rules = userConfig.rules || {};

    for (const plugin of cli.plugin) {
        userConfig.plugins.push(plugin);
    }

    for (const rule of cli.rule) {
        // If no ":" was found, it means only the rule's name was specified.
        // Treat it as an error and adopt its default configuration options.
        if (!rule.includes(":")) {
            userConfig.rules[rule] = "error";
            continue;
        }

        let [key, value] = rule.split(":").map(i => i.trim());
        try {
            value = JSON.parse(value);
        } catch (e) {
            errorReporter.reportFatal(`There was an error trying to parse '${rule}': ${e.message}`);
            process.exit(errorCodes.INVALID_PARAMS);
        }
        userConfig.rules[key] = value;
    }

    //get all files & folders to ignore from .soliumignore
    if (cli.soliumignore) {
        try {
            ignore = fs.readFileSync(SOLIUMIGNORE_FILENAME_ABSOLUTE, "utf8").split(EOL);
        } catch (e) {
            if (e.code === "ENOENT") {
                errorReporter.reportInternal(
                    "No '.soliumignore' found. Use --no-soliumignore to make this warning go away.");
            } else {
                errorReporter.reportInternal(`Failed to read '.soliumignore': ${e.message}`);
            }
        }
    }

    if (cli.hot) {
        // --hot is equivalent to --watch in functionality, is a legacy option
        cli.watch = true;
    }

    if (cli.watch) {
        if (cli.stdin) {
            return errorReporter.reportFatal("Cannot watch files when reading from stdin");
        }

        if (cli.fix) {
            return errorReporter.reportFatal("Automatic code formatting is not supported in watch mode.");
        }
    }

    let errorCount = lint(userConfig, { file: cli.file, dir: cli.dir, stdin: cli.stdin }, ignore, errorReporter);

    if (cli.watch) {

        let spy = chokidar.watch(CWD);

        spy.on("change", function() {
            console.log("\x1Bc"); // clear the console
            console.log(`File change detected. Start linting.${EOL}`);
            lint(userConfig, { file: cli.file, dir: cli.dir }, ignore, errorReporter);	//lint on subsequent changes (hot)
            console.log(`Linting complete. Watching for file changes.${EOL}`);
        });

    } else if (errorCount > 0) {
        process.exit(errorCodes.ERRORS_FOUND);
    }
}
function execute(programArgs) {

    let userConfig = {}, ignore, errorReporter;

    createCliOptions(cli);
    programArgs.length === 2 ? cli.help() : cli.parse(programArgs);

    if (cli.init) {
        return setupDefaultUserConfig();
    }

    try {
        errorReporter = getErrorReporter(cli.reporter);
    } catch (e) {
        process.stderr.write(`[Fatal error] ${e.message}${EOL}`);
        process.exit(errorCodes.INVALID_PARAMS);
    }

    if (cli.soliumrc) {
        /**
         * If cli.config option is NOT specified, then resort to .soliumrc in current dir.
         * Else,
         *   If path is absolute, assign as-it-is.
         *   Else (relative pathing) join path with current dir.
         */
        const soliumrcAbsPath = cli.config ?
            (path.isAbsolute(cli.config) ? cli.config : path.join(CWD, cli.config)) :
            SOLIUMRC_FILENAME_ABSOLUTE;

        try {
            userConfig = require(soliumrcAbsPath);
        } catch (e) {
            // Check if soliumrc file exists. If yes, then the file is in an invalid format.
            if (fs.existsSync(soliumrcAbsPath)) {
                errorReporter.reportFatal(`An invalid ${SOLIUMRC_FILENAME} was provided. ${e.message}`);
            } else {
                if (cli.config) {
                    errorReporter.reportFatal(`${soliumrcAbsPath} does not exist.`);
                } else {
                    errorReporter.reportFatal(`Couldn't find ${SOLIUMRC_FILENAME} in the current directory.`);
                }
            }

            process.exit(errorCodes.NO_SOLIUMRC);
        }
    }

    //if custom rules' file is set, make sure we have its absolute path
    if (
        userConfig ["custom-rules-filename"] &&
        !path.isAbsolute(userConfig ["custom-rules-filename"])
    ) {
        userConfig ["custom-rules-filename"] = path.join(
            CWD, userConfig ["custom-rules-filename"]
        );
    }

    // Pass cli arguments that modify the behaviour of upstream functions.
    userConfig.options = {
        autofix: Boolean(cli.fix),
        autofixDryrun: Boolean(cli.fixDryRun),
        debug: Boolean(cli.debug)
    };

    if (userConfig.options.autofixDryrun) {
        if (userConfig.options.autofix) {
            return errorReporter.reportFatal("Cannot use both --fix and --fix-dry-run");
        }
        if (cli.reporter != "pretty") {
            return errorReporter.reportFatal("Option --fix-dry-run is only supported with pretty reporter");
        }
    }

    userConfig.plugins = userConfig.plugins || [];
    userConfig.rules = userConfig.rules || {};

    for (const plugin of cli.plugin) {
        userConfig.plugins.push(plugin);
    }

    for (const rule of cli.rule) {
        // If no ":" was found, it means only the rule's name was specified.
        // Treat it as an error and adopt its default configuration options.
        if (!rule.includes(":")) {
            userConfig.rules[rule] = "error";
            continue;
        }

        let [key, value] = rule.split(":").map(i => i.trim());
        try {
            value = JSON.parse(value);
        } catch (e) {
            errorReporter.reportFatal(`There was an error trying to parse '${rule}': ${e.message}`);
            process.exit(errorCodes.INVALID_PARAMS);
        }
        userConfig.rules[key] = value;
    }

    //get all files & folders to ignore from .soliumignore
    if (cli.soliumignore) {
        try {
            ignore = fs.readFileSync(SOLIUMIGNORE_FILENAME_ABSOLUTE, "utf8").split(EOL);
        } catch (e) {
            if (e.code === "ENOENT") {
                errorReporter.reportInternal(
                    "No '.soliumignore' found. Use --no-soliumignore to make this warning go away.");
            } else {
                errorReporter.reportInternal(`Failed to read '.soliumignore': ${e.message}`);
            }
        }
    }

    if (cli.hot) {
        // --hot is equivalent to --watch in functionality, is a legacy option
        cli.watch = true;
    }

    if (cli.watch) {
        if (cli.stdin) {
            return errorReporter.reportFatal("Cannot watch files when reading from stdin");
        }

        if (cli.fix) {
            return errorReporter.reportFatal("Automatic code formatting is not supported in watch mode.");
        }
    }

    let errorCount = lint(userConfig, { file: cli.file, dir: cli.dir, stdin: cli.stdin }, ignore, errorReporter);

    if (cli.watch) {

        let spy = chokidar.watch(CWD);

        spy.on("change", function() {
            console.log("\x1Bc"); // clear the console
            console.log(`File change detected. Start linting.${EOL}`);
            lint(userConfig, { file: cli.file, dir: cli.dir }, ignore, errorReporter);	//lint on subsequent changes (hot)
            console.log(`Linting complete. Watching for file changes.${EOL}`);
        });

    } else if (errorCount > 0) {
        process.exit(errorCodes.ERRORS_FOUND);
    }
}
Entry point to the CLI reponsible for initiating linting process based on command-line arguments
@param {Array} programArgs Commandline arguments