Source: cli.js

/**
 * Command-line interface.
 * 
 * @module cli
 */

/*jshint boss:true, laxbreak:true*/


function resourceListToString(resourceList, short) {
    var nK = resourceList.length,
        result = ["\nAvailable resources (", nK, "):\n"],
        sIndent = "    ",
        nI, resource;
    for (nI = 0; nI < nK; nI++) {
        resource = resourceList[nI];
        if (short) {
            result.push("\n",
                    sIndent, "* ", resource.name, " (", resource.url, ") - ", resource.description);
        }
        else {
            result.push("\n",
                    sIndent, resource.name, " - ", resource.description, "\n",
                    sIndent, "url: ", resource.url, "\n",
                    sIndent, "tags: ", resource.tag.join(" "), "\n");
            if (resource.note) {
                result.push(sIndent, resource.note, "\n");
            }
        }
    }
    return result.join("");
}


var fs = require("fs"),
    
    charm = require("charm")(),
    nomnom = require("nomnom"),
    
    formatUnit = require("./format"),
    resourceUnit = require("./resource"),
    seeq = require("./seeq"),
    
    pkg = JSON.parse(fs.readFileSync(__dirname + "/../package.json", "utf8")),
    resourceList = resourceUnit.getList({includeApi: true}),
    generalSettingName = {
        "partialMatch": null, 
        "caseSensitive": null, 
        "search": null, 
        "limit": null
    },
    
    argParser = nomnom()
                    .script(pkg.name)
                    .options({
                        "name": {
                            position: 0,
                            list: true,
                            help: "Name/string that should be searched for or checked for presence on a resource"
                        },
                        "help": {
                            abbr: "h",
                            help: "Show usage information and exit"
                        },
                        "listResource": {
                            abbr: "l",
                            full: "list-resource",
                            flag: true,
                            help: "Show information about all available resources"
                        },
                        "resource": {
                            abbr: "r",
                            full: "at",
                            help: "Filter for available resources by name: comma-separated list of names (case-insensitive) of resources that should be checked/searched"
                        },
                        "resourceTag": {
                            abbr: "t",
                            full: "tag",
                            help: "Filter for available resources by tag: comma-separated list of tags (case-insensitive); -tag means that resource should not have the tag"
                        },
                        "checkAllTags": {
                            full: "all-tag",
                            flag: true,
                            help: "Whether all specified tags should be checked for a resource"
                        },
                        "partialMatch": {
                            abbr: "p",
                            full: "partial-match",
                            help: "Allow partial matching when checking name: 0 - disallow (by default), 1 - allow at the beginning of matching strings, 2 - allow substring matching",
                            choices: [0, 1, 2]
                        },
                        "caseSensitive": {
                            abbr: "c",
                            full: "case-sensitive",
                            flag: true,
                            help: "Use case-sensitive check/search when possible"
                        },
                        "search": {
                            abbr: "s",
                            flag: true,
                            help: "Make search instead of check"
                        },
                        "limit": {
                            abbr: "m",
                            help: "Limit of quantity of results per resource",
                            callback: function(value) {
                                if (value < 1) {
                                    return "Limit should be equal to or greater than 1";
                                }
                            }
                        },
                        "format": {
                            abbr: "f",
                            "default": formatUnit.exists("text") ? "text" : "raw",
                            help: "Result format; can be: " + formatUnit.getNameList().join(", ")
                        },
                        "verbose": {
                            abbr: "V",
                            flag: true,
                            help: "Enable verbose output"
                        },
                        "version": {
                            abbr: "v",
                            flag: true,
                            help: "Show program version"
                        }
                    })
                    .help(resourceListToString(resourceList, true));


(function() {
    var nI, nL, settings, sName, value;
    // Add options of resources
    for (nI = 0, nL = resourceList.length; nI < nL; nI++) {
        value = resourceList[nI];
        if (settings = value.api.settings) {
            sName = value.id;
            for (value in settings) {
                argParser.option(sName + "-" + value, settings[value]);
            }
        }
    }
}());


function showProgress(data) {
    var sOut = [data.number, "/", data.total, " (", Math.floor(data.number * 100 / data.total), "%)"].join("");
    charm.left(showProgress.shift);
    charm.write(sOut);
    showProgress.shift = sOut.length;
    if (data.number === data.total) {
        charm.write("\n");
    }
}
showProgress.shift = 3;


function showResult(resultMap, nameList, args) {
    var sFormat = args.format,
        result = sFormat ? formatUnit.exists(sFormat) : false;
    if (result) {
        result = formatUnit.format(resultMap, 
                                    sFormat,
                                    {
                                        queryList: nameList,
                                        verbose: args.verbose
                                    });
    }
    else {
        result = JSON.stringify(resultMap, null, 4);
    }
    console.log("\nResults:\n\n" + result);
}


/**
 * Perform operation using specified options.
 * 
 * @param {Object} [args]
 *      Operation options.
 * @alias module:cli.run
 */
function run(args) {
    var bShowUsage = true,
        list,
        nameList,
        nL,
        resourceNameList,
        resourceSettings,
        sName,
        value;
    
    if (! args) {
        args = {};
    }
    
    if (args.version) {
        console.log("Version: " + pkg.version);
        bShowUsage = false;
    }
    
    if (args.listResource) {
        console.log(resourceListToString(resourceList));
        bShowUsage = false;
    }
    
    if (args.name && args.name.length) {
        // List of names to check
        nameList = args.name;
        // Determine resources to check
        if (args.resource) {
            args.resource = args.resource.split(",");
        }
        if (args.resourceTag) {
            args.resourceTag = args.resourceTag.split(",");
        }
        resourceNameList = resourceUnit.getNameList({
                                                        selectName: args.resource, 
                                                        selectTag: args.resourceTag,
                                                        checkAllTags: args.checkAllTags
                                                    });
        // Make check if resources are specified
        if (resourceNameList.length) {
            // Prepare resources settings
            resourceSettings = {
            };
            for (sName in args) {
                value = args[sName];
                // General settings
                if (sName in generalSettingName) {
                    (resourceSettings._general || (resourceSettings._general = {}))[sName] = value;
                }
                // Resource-specific settings
                else if (list = /^(\w+)\-(.+)$/.exec(sName)) {
                    if (sName = resourceUnit.getIdByName(list[1])) {
                        ( resourceSettings[sName] || (resourceSettings[sName] = {}) )[ list[2] ] = value;
                    }
                }
            }
            // Start checking
            console.log("Checking " + resourceNameList.join(", ") + "...");
            if (nameList.length > 1 || resourceNameList.length > 1) {
                value = showProgress;
                charm.pipe(process.stdout);
                charm.write("Progress: 0 %");
            }
            else {
                value = null;
            }
            seeq.search(nameList, 
                        function(resultMap) {
                            showResult(resultMap, nameList, args);
                        },
                        {
                            resource: resourceNameList, 
                            settings: resourceSettings,
                            progressCallback: value
                        });
        }
        // If no resource is found
        else {
            console.log("No resource is found.");
            if (args.resource) {
                list = args.resource.filter(function(name) {
                    return ! resourceUnit.isAvailable(name);
                });
                if (nL = list.length) {
                    console.log(nL > 1
                                    ? "The following resources are unknown: " + list.join(", ")
                                    : list[0] + " is unknown resource");
                }
            }
            console.log("Run `" + pkg.name + " -l` to see information about all available resources.");
        }
    }
    else if (bShowUsage) {
        argParser.print(argParser.getUsage());
    }
}


/**
 * Perform operation specified via command-line arguments.
 * 
 * @param {Object} [options]
 *      Predefined values for command-line options.
 *      Each option specified in this object will be used only when the corresponding option is not set in command-line arguments.
 * @alias module:cli.cli
 * @see {@link module:cli.run run}
 */
function cli(options) {
    var args = argParser.parse(),
        optionMap,
        sName,
        value;
    
    // Use predefined values for absent arguments
    if (options) {
        optionMap = argParser.specs;
        for (sName in optionMap) {
            if (! (sName in args)) {
                if (sName in options) {
                    args[sName] = options[sName];
                }
                else {
                    value = optionMap[sName];
                    if (value.full in options) {
                        args[sName] = options[value.full];
                    }
                    else if (value.abbr in options) {
                        args[sName] = options[value.abbr];
                    }
                }
            }
        }
    }
    // Run CLI
    run(args);
}


// Exports

exports.cli = cli;
exports.run = run;


// If script is run directly from Node
if (require.main === module) {
    cli();
}
Copyright (c) 2014 Denis Sikuler
Documentation generated by JSDoc 3.2.2 on Thu Aug 21 2014 23:46:51 GMT+0400 (MSK) using the DocStrap template.