lib/builder/type-builder.js
// 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);
}