<commit_before>var VM = require('vm'),
    Q = require('q'),
    QFS = require('q-fs'),
    INHERIT = require('inherit'),
    APW = require('apw'),
    PATH = require('./path'),
    UTIL = require('util'),
    BEMUTIL = require('./util'),
    Node = require('./nodes/node'),
    registry = {};

exports.DEFAULT_WORKERS = 10;

exports.APW = INHERIT(APW, {

    findAndProcess: function(targets) {
        if (!Array.isArray(targets)) targets = [targets];
        var _this = this,
            foundNodes = targets.map(function(t) {
                return _this.findNode(t);
            });
        return Q.all(foundNodes)
            .fail(function(err) {
                if (typeof err === 'string') return;
                return Q.reject(err);
            })
            .then(function() {
                return _this.process(targets);
            });
    },

    // TODO: move node introspection logic to the node in arch
    findNode: function(id, head, tail) {
        head = head || '';
        tail = tail || id;

        if (this.arch.hasNode(id)) return Q.ref(id);
        if (head == id) return Q.reject(UTIL.format('Node "%s" not found', id));

        var parts = tail.split(PATH.dirSep),
            p = parts.shift();
        head = (head? [head, p] : [p]).join(PATH.dirSep);
        tail = parts.join(PATH.dirSep);

        var _this = this,
            magicHead = head + '*';
        if (!this.arch.hasNode(magicHead)) {
            return this.findNode(id, head, tail);
        }

        return this.process(magicHead).then(function() {
            return _this.findNode(id, head, tail);
        });
    }

});

exports.createArch = function(root) {

    var arch = new APW.Arch(),
        rootMakefile = PATH.join(root, '.bem', 'make.js');

    return QFS.exists(rootMakefile)
        .then(function(exists) {

            if (!exists) return false;

            return BEMUTIL.readFile(rootMakefile).then(function(content) {
                VM.runInNewContext(
                    content,
                    {
                        MAKE: Make,
                        console: console,
                        require: function(path){
                            if (path.match(/^\./)){
                                path = PATH.resolve(PATH.dirname(rootMakefile), path);
                            }
                            return require(path);
                        }
                    },
                    rootMakefile);

                return true;
            });
        })
        .then(function(exists) {
            var regArch = Make.getRegistry('arch'),
                Arch = regArch || require('./default-arch').Arch;
            return new Arch(arch, root).alterArch();
        });

};

var Make = exports.NodesRegistry = {

    decl: function(nodeName, objectOrBaseName, object) {

        var baseName = object? objectOrBaseName : nodeName,
            base = Make.getNodeClass(baseName);

        if (object && !base) throw new Error('Unknown base node ' + baseName);

        registry[nodeName] = INHERIT(base || Node, object || objectOrBaseName);

        return registry;
    },

    arch: function(object) {
        var base = Make.getRegistry('arch') || require('./default-arch').Arch;
        registry['arch'] = INHERIT(base, object);
    },

    getRegistry: function(node) {
        return node? registry[node] : registry;
    },

    getNodeClass: function(nodeName){
        return Make.getRegistry(nodeName) || require('./nodes')[nodeName];
    }

};<commit_msg>- Make.decl fixed to work with classes (built using INHERIT) - default arch can be overriden using Make.decl('Arch', …) close #95<commit_after>var VM = require('vm'),
    Q = require('q'),
    QFS = require('q-fs'),
    INHERIT = require('inherit'),
    APW = require('apw'),
    PATH = require('./path'),
    UTIL = require('util'),
    BEMUTIL = require('./util'),
    LOGGER = require('./logger'),
    registry = {};

exports.DEFAULT_WORKERS = 10;

exports.APW = INHERIT(APW, {

    findAndProcess: function(targets) {
        if (!Array.isArray(targets)) targets = [targets];
        var _this = this,
            foundNodes = targets.map(function(t) {
                return _this.findNode(t);
            });
        return Q.all(foundNodes)
            .fail(function(err) {
                if (typeof err === 'string') return;
                return Q.reject(err);
            })
            .then(function() {
                return _this.process(targets);
            });
    },

    // TODO: move node introspection logic to the node in arch
    findNode: function(id, head, tail) {
        head = head || '';
        tail = tail || id;

        if (this.arch.hasNode(id)) return Q.ref(id);
        if (head == id) return Q.reject(UTIL.format('Node "%s" not found', id));

        var parts = tail.split(PATH.dirSep),
            p = parts.shift();
        head = (head? [head, p] : [p]).join(PATH.dirSep);
        tail = parts.join(PATH.dirSep);

        var _this = this,
            magicHead = head + '*';
        if (!this.arch.hasNode(magicHead)) {
            return this.findNode(id, head, tail);
        }

        return this.process(magicHead).then(function() {
            return _this.findNode(id, head, tail);
        });
    }

});

exports.createArch = function(root) {

    var arch = new APW.Arch(),
        rootMakefile = PATH.join(root, '.bem', 'make.js');

    // Register default arch in the registry to be available for Make.decl()
    Make.decl('Arch', require('./default-arch').Arch);

    return QFS.exists(rootMakefile)
        .then(function(exists) {

            if (!exists) return false;

            return BEMUTIL.readFile(rootMakefile).then(function(content) {
                VM.runInNewContext(
                    content,
                    {
                        MAKE: Make,
                        console: console,
                        require: function(path){
                            if (path.match(/^\./)){
                                path = PATH.resolve(PATH.dirname(rootMakefile), path);
                            }
                            return require(path);
                        }
                    },
                    rootMakefile);

                return true;
            });
        })
        .then(function(exists) {
            return new (Make.getRegistry('Arch'))(arch, root).alterArch();
        });

};

var Make = exports.NodesRegistry = {

    decl: function(nodeName, objectOrBaseName, object) {

        var baseName = object? objectOrBaseName : nodeName,
            base = Make.getNodeClass(baseName);

        if (object && !base) throw new Error('Unknown base node ' + baseName);

        object = object || objectOrBaseName;

        registry[nodeName] = typeof object === 'function'? object: INHERIT(base || require('./nodes/node').Node, object);

        return registry;
    },

    getRegistry: function(node) {
        return node? registry[node] : registry;
    },

    getNodeClass: function(nodeName){
        return Make.getRegistry(nodeName) || require('./nodes')[nodeName];
    }
};
{'fraction_non_alphanumeric': 0.14027466367713004, 'fraction_numerical': 0.0008408071748878924, 'mean_word_length': 1.7240458015267175, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '4385116', 'n_tokens_mistral': 2048, 'n_tokens_neox': 1951, 'n_words': 441}