<commit_before>var async = require('async');
var fs = require('fs');
var readline = require('readline');
var validator = require('validator');
var sprintf = require('sprintf');
var Heap = require('heap');

function Interrogator() {
}

var nullFormatter = function(txt) { return txt; };

Interrogator.prototype.descriptionFormatter = nullFormatter;
Interrogator.prototype.promptFormatter = nullFormatter;
Interrogator.prototype.errorFormatter = nullFormatter;

Interrogator.prototype.optionLineFormatter = function(k, v) {
    return sprintf("%5s. %s", k, v);
};

Interrogator.prototype.optionsFormatter = function(options) {
    var optKeys = new Heap(function(a, b) { return a - b; });
    var optStrings = [];

    for(var i in options) {
        optKeys.push(i);
    }

    while(!optKeys.empty()) {
        var i = optKeys.pop();
        optStrings.push(this.optionLineFormatter(i, options[i]));
    }

    return optStrings.join("\n");
};

Interrogator.prototype.run = function(questions, callback) {
    var obj = {};
    this.updateObject(obj, questions, function(err) {
        return callback(err, obj);
    }.bind(this));
};

Interrogator.prototype.updateObject = function(obj, questions, callback) {
    var self = this;
    var tasks = [];

    questions.forEach(function(question) {
        if(typeof obj[question.name] !== "undefined") {
            if(question.runAfter) {
                tasks.push(function(callback) {
                    question.runAfter(obj[question.name], callback);
                });
            }

            return;
        }

        tasks.push(function(callback) {
            self.question(question, function(err, result) {
                obj[question.name] = result;
                return callback(err);
            });
        });
    });

    async.series(tasks, function(err) {
        return callback(err);
    });
};

Interrogator.prototype.question = function(question, callback) {
    var self = this;

    question.prompttext = question.prompttext || " > ";
    question.error = question.error || "A response is required.";

    if(question.optionsFetcher) {
        return question.optionsFetcher(function(err, options) {
            if(err) {
                return callback(err);
            }

            question.options = options;
            delete question.optionsFetcher;
            return self.question(question, callback);
        });
    }

    if(question.description) {
        process.stdout.write(self.descriptionFormatter(question.description) + "\n");
    }

    if(question.options) {
        process.stdout.write(self.optionsFormatter(question.options) + "\n");
    }

    var rl = readline.createInterface({input: process.stdin, output: process.stdout});
    rl.question(self.promptFormatter(question.prompttext), function(answer) {
        rl.close();

        answer = validator.trim(answer);
        if(question.required && answer == "") {
            process.stdout.write(self.errorFormatter(question.error) + "\n");
            return self.question(question, callback);
        }

        answer = validator.trim(answer) || question.default;<commit_msg>use read instead of readline; support silent option<commit_after>var async = require('async');
var fs = require('fs');
var read = require('read');
var validator = require('validator');
var sprintf = require('sprintf');
var Heap = require('heap');

function Interrogator() {
}

var nullFormatter = function(txt) { return txt; };

Interrogator.prototype.descriptionFormatter = nullFormatter;
Interrogator.prototype.promptFormatter = nullFormatter;
Interrogator.prototype.errorFormatter = nullFormatter;

Interrogator.prototype.optionLineFormatter = function(k, v) {
    return sprintf("%5s. %s", k, v);
};

Interrogator.prototype.optionsFormatter = function(options) {
    var optKeys = new Heap(function(a, b) { return a - b; });
    var optStrings = [];

    for(var i in options) {
        optKeys.push(i);
    }

    while(!optKeys.empty()) {
        var i = optKeys.pop();
        optStrings.push(this.optionLineFormatter(i, options[i]));
    }

    return optStrings.join("\n");
};

Interrogator.prototype.run = function(questions, callback) {
    var obj = {};
    this.updateObject(obj, questions, function(err) {
        return callback(err, obj);
    }.bind(this));
};

Interrogator.prototype.updateObject = function(obj, questions, callback) {
    var self = this;
    var tasks = [];

    questions.forEach(function(question) {
        if(typeof obj[question.name] !== "undefined") {
            if(question.runAfter) {
                tasks.push(function(callback) {
                    question.runAfter(obj[question.name], callback);
                });
            }

            return;
        }

        tasks.push(function(callback) {
            self.question(question, function(err, result) {
                obj[question.name] = result;
                return callback(err);
            });
        });
    });

    async.series(tasks, function(err) {
        return callback(err);
    });
};

Interrogator.prototype.question = function(question, callback) {
    var self = this;

    question.prompttext = question.prompttext || " > ";
    question.error = question.error || "A response is required.";

    if(question.optionsFetcher) {
        return question.optionsFetcher(function(err, options) {
            if(err) {
                return callback(err);
            }

            question.options = options;
            delete question.optionsFetcher;
            return self.question(question, callback);
        });
    }

    if(question.description) {
        process.stdout.write(self.descriptionFormatter(question.description) + "\n");
    }

    if(question.options) {
        process.stdout.write(self.optionsFormatter(question.options) + "\n");
    }

    var readOptions = {
        "prompt": question.prompttext,
        "silent": question.silent
    };

    read(readOptions, function(err, answer, isDefault) {
        if(err) {
            return callback(err, null);
        }

        answer = validator.trim(answer);
        if(question.required && answer == "") {
            process.stdout.write(self.errorFormatter(question.error) + "\n");
            return self.question(question, callback);
        }

        answer = answer || question.default;
{'fraction_non_alphanumeric': 0.13571090421335016, 'fraction_numerical': 0.00031560675398453525, 'mean_word_length': 2.6093394077448746, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5588506', 'n_tokens_mistral': 1777, 'n_tokens_neox': 1730, 'n_words': 333}