enricostara/telegram-tl-node

View on GitHub
lib/builder/type-builder.js

Summary

Maintainability
B
4 hrs
Test Coverage
//     telegram-tl-node
//     Copyright 2014 Enrico Stara 'enrico.stara@gmail.com'
//     Released under the MIT License
//     https://github.com/enricostara/telegram-tl-node

/*jshint evil:true */

// Export the method
exports.buildType = buildType;
exports.buildTypeFunction = buildTypeFunction;
exports.buildTypes = buildTypes;
exports.inheritsTlSchema = inheritsTlSchema;
exports.registerTypeById = registerTypeById;
exports.requireTypeFromBuffer = requireTypeFromBuffer;
exports.registerTypeByName = registerTypeByName;
exports.requireTypeByName = requireTypeByName;

// Import dependencies
var ConstructorBuilder = require('./constructor-builder');
var util = require('util');
var utility = require('../utility');
var getLogger = require('get-log');
var logger = getLogger('TypeBuilder');

// Extend the 'constructor' with the Type generated by the 'superTLSchema'
function inheritsTlSchema(constructor, superTlSchema) {
    var NewType = buildType('abstract', superTlSchema);
    util.inherits(constructor, NewType);
    constructor.s_ = NewType;
    constructor.super_ = NewType.super_;
    constructor.util = NewType.util;
    constructor.requireTypeByName = NewType.requireTypeByName;
    constructor.requireTypeFromBuffer = NewType.requireTypeFromBuffer;
    constructor.logger = NewType.logger;
}

// Types builder
function buildTypes(schemas, types, targetModule, isTypeFunction) {
    for (var i = 0; i < schemas.length; i++) {
        var type = schemas[i];
        // Vector is already defined by class TypeVector
        if ('vector' !== type.predicate &&
            ( !types || types.indexOf(type[isTypeFunction ? 'method' : 'type']) > -1)) {
            var typeName;
            if (isTypeFunction) {
                typeName = type.method;
                var newFunction = buildTypeFunction(targetModule._id, type);
                setType(typeName, targetModule, newFunction, true);
            } else {
                typeName = type.predicate;
                var newConstructor = buildType(targetModule._id, type);
                setType(typeName, targetModule, newConstructor, false);
            }
        }
    }
}
function setType(typeName, targetModule, type, isTypeFunction) {
    if (targetModule && typeName && typeName.length > 0) {
        var index = typeName.indexOf('.');
        if (index < 0) {
            typeName = isTypeFunction ? typeName : utility.capitalize(typeName);
            return targetModule[typeName] = type;
        } else if (index === 0) {
            setType(typeName.slice(1), targetModule, type, isTypeFunction);
        } else if (index === (typeName.length - 1)) {
            setType(typeName.slice(0, -1), targetModule, type, isTypeFunction);
        }
        else {
            var pkg = typeName.slice(0, index);
            targetModule[pkg] = targetModule[pkg] ? targetModule[pkg] : {};
            setType(typeName.slice(index + 1), targetModule[pkg], type, isTypeFunction);
        }
    }
}
// Build a new `TypeLanguage` type parsing the `TL-Schema constructor`
function buildType(module, tlSchema) {
    return new ConstructorBuilder(module, tlSchema).getType();
}

// Build a new `TypeLanguage` function parsing the `TL-Schema method`
function buildTypeFunction(module, tlSchema) {
    var methodName = tlSchema.method;
    // Start creating the body of the new Type function
    var body =
        '\tvar self = arguments.callee;\n' +
        '\tvar callback = options.callback;\n' +
        '\tvar channel = options.channel;\n' +
        '\tif (!channel) {\n' +
        '\t\tvar msg = \'The \\\'channel\\\' option is missing, it\\\'s mandatory\';\n' +
        '\t\tself.logger.error(msg);\n' +
        '\t\tif(callback) {\n' +
        '\t\t\tcallback(new TypeError(msg));\n' +
        '\t\t}\n' +
        '\t\treturn;\n' +
        '\t}\n';
    body +=
        '\tvar reqPayload = new self.Type(options);\n' +
        '\tchannel.callMethod(reqPayload, callback);\n';
    if (logger.isDebugEnabled()) {
        logger.debug('Body for %s type function:', methodName);
        logger.debug('\n' + body);
    }
    // Create the new Type function
    var typeFunction = new Function('options', body);
    typeFunction._name = methodName;
    typeFunction.requireTypeFromBuffer = ConstructorBuilder.requireTypeFromBuffer;
    // Create the function payload class re-calling TypeBuilder constructor.
    typeFunction.Type = new ConstructorBuilder(module, tlSchema, true).getType();
    typeFunction.logger = getLogger(module + '.' + methodName);
    return typeFunction;
}

function registerTypeById(type) {
    ConstructorBuilder.registerTypeById(type);
}

function requireTypeFromBuffer(buffer) {
    return ConstructorBuilder.requireTypeFromBuffer(buffer);
}

function registerTypeByName(name, type) {
    ConstructorBuilder.registerTypeByName(name, type);
}

function requireTypeByName(name, type) {
    return ConstructorBuilder.requireTypeByName(name, type);
}