lib/modules/importHelper.js

Summary

Maintainability
D
2 days
Test Coverage
//////////////////////////////////////////
// Requirements                         //
//////////////////////////////////////////

var validate          = require('./../util/validate');
var semlog            = require('semlog');
var log               = semlog.log;


//////////////////////////////////////////
// Variables                            //
//////////////////////////////////////////

/** Default settings */
exports.settings = {
    arraymapSeparator: ';'
};


//////////////////////////////////////////
// FUNCTIONS                            //
//////////////////////////////////////////

exports.setSettings = function(settings) {
    exports.settings = settings;
};


/**
 * Converts an object to a wikitext template
 *
 * @param {string}      name    name of the template
 * @param {object}      obj
 *
 * @returns {string}    wikitext
 */
exports.objToTemplate = function(name, obj) {

    if (!obj || Object.keys(obj).length === 0) {
        return '{{' + name + '}}\n'; // No unnecessary linebreaks
    }

    var wikitext = '{{' + name + '\n';

    for (var propertyName in obj) {
        var property = obj[propertyName];

        if (property && typeof property === 'object' && !(property instanceof Array)) {
            // Handle Objects
            log('[W] importHelper.objToTemplate() cannot convert objects to template values!');
        } else if (property === null) {
            // Handle properties without value
            wikitext += '|' + propertyName + '\n';
        } else if (Array.isArray(property)) {
            // Handle Arrays
            wikitext += '|' + propertyName + '=' + property.join(exports.settings.arraymapSeparator + ' ') + '\n';
        } else if (property instanceof Boolean) {
            // Handle Booleans
            // TODO: This needs to be adjustable/localizable
            if (property === true) {
                property = 'Ja';
            } else {
                property = 'Nein';
            }
            wikitext += '|' + propertyName + '=' + property + '\n';
        } else {
            wikitext += '|' + propertyName + '=' + property + '\n';
        }

    }

    wikitext += '}}\n';

    return wikitext;
};

/**
 * Converts an object to a MediaWiki parser function call
 *
 * @param {string}      name    name of the function
 * @param {object}      obj
 *
 * @returns {string}    wikitext
 */
exports.objToFunction = function(name, obj) {

    var wikitext = '{{' + name + ':\n';

    for (var propertyName in obj) {

        var prop = obj[propertyName];

        if (prop && typeof prop === 'object' && !(obj instanceof Array)) {
            log('[W] importHelper.objToFunction() cannot convert objects to function parameters!');
        } else if (prop === true) {
            wikitext += '|' + propertyName + '\n';
        } else if (Array.isArray(prop)) {
            wikitext += '|' + propertyName + '=' + prop.join(exports.settings.arraymapSeparator) + '\n';
        } else {
            wikitext += '|' + propertyName + '=' + prop.toString().trim() + '\n';
        }
    }

    wikitext += '}}\n';

    return wikitext;

};


/**
 * Converts a collection of wikitext, templates and function calls to a combined wikitext document
 * See the example object for the objCollection object structure
 *
 * @example
 * var example = [
 * '==Pure Wikitext==',
 * {
 *     name: 'Person',
 *     template: {
 *        email: 'rosalind.chan@optique.biz',
 *        phone: '+1 (864) 421-2744'
 *     }
 * },
 * {
 *     name: '#set',
 *     function: {
 *         var1: 1,
 *         var2: 'zwei'
 *     }
 * }];
 *
 * @param objCollection
 * @returns {string}
 */
exports.objCollectionToWikitext = function(objCollection) {

    var wikitext = '';

    for (var i = 0; i < objCollection.length; i++) {

        var obj = objCollection[i];

        if (typeof obj === 'string') {
            wikitext += obj + '\n';
        } else if (typeof obj === 'object' && obj.function) {
            wikitext += exports.objToFunction(obj.name, obj.function);
        } else if (typeof obj === 'object') {
            // If no data is given, asume it's an empty template
            var template = obj.template || {};
            wikitext += exports.objToTemplate(obj.name, template);
        }
    }

    return wikitext;
};

/**
 * Validates an object collection against the mobo registry
 * @param objCollection
 * @param registry
 */
exports.validate = function(objCollection, registry) {

    var errors = 0;

    for (var i = 0; i < objCollection.length; i++) {
        var obj = objCollection[i];

        if (typeof obj === 'object' && obj.name && obj.template) {

            if (registry && registry.expandedModel[obj.name]) {
                var result = validate.validate(obj.template, registry.expandedModel[obj.name], obj.name);
                if (exports.settings.verbose) {
                    log('[D] Validated: ' + obj.name + ' with ' + result.errors.length + ' errors.');
                }
                if (result.errors && result.errors.length > 0) {
                    log(obj.template);
                    errors += result.errors.length;
                }

            } else {
                log('[E] Model "' + obj.name + '" not found in registry');
            }
        }
    }

    return errors;

};


exports.enhanceWithForm = function(objCollection, formSchema) {

    if (formSchema && formSchema.$path) {

        var newCollection = [];
        var inserted = [];

        log(' ');
        if (exports.settings.verbose) {
            log('[D] Enhancing import collection with ' + formSchema.$path);
        }

        for (var templateName in formSchema.properties) {

            var template = formSchema.properties[templateName];

            if (template.$reference && template.$reference.type === 'smw_template') {

                // Handle wikitext templates

                //log('[D] Inserting empty template: ' + template.id);
                newCollection.push({
                    name: template.id,
                    template: {}
                });

            } else if (template.$reference && template.$reference.type === 'model') {

                // Handle single-instance models

                var item = exports.findInCollection(objCollection, template.id);

                if (item.length === 1) {
                    //log('[D] Inserting single instance template: ' + template.id);

                    newCollection.push({
                        name: template.id,
                        template: item[0].template || {}
                    });
                    inserted.push(template.id);
                } else {
                    newCollection.push({
                        name: template.id,
                        template: {}
                    });
                }

                if (item.length > 1) {
                    log('[W] Cannot add a single instance template more than once: ' + template.id);
                }

            } else if (template.items && template.items.$reference.type === 'model') {

                // Handle multiple-instance models

                var items = exports.findInCollection(objCollection, templateName);

                for (var i = 0; i < items.length; i++) {
                    if (exports.settings.verbose) {
                        log('[D] Inserting multiple instance template: ' + templateName);
                    }
                    newCollection.push(items[i]);
                    inserted.push(templateName);
                }

            } else if (template.wikitext) {

                // Ignore "wikitext" properties, since they'll only be rendered on the form edit page
                if (exports.settings.debug) {
                    log('[D] Ignoring form-only "wikitext" injection');
                }
            } else {
                log('[W] Unknown template type: ' + template.id);
                log(template);
            }

        }

        // Automatically add the FormEdit Category if the formEditHelper is enabled
        if (exports.settings.formEditHelper) {
            newCollection.push('{{' + formSchema.id + ' FormEdit}}');
        }

        // Automatically add the HeaderTabs closing template if the setting is enabled
        if (exports.settings.headerTabs) {
            newCollection.push('{{HeaderTabs}}');
        }

        // Add all items from the object collection that haven't been added yet
        // They will be appended at the bottom
        for (var j = 0; j < objCollection.length; j++) {

            var obj = objCollection[j];

            // If the item has not been inserted already
            if (obj.name && inserted.indexOf(obj.name) === -1) {

                if (exports.settings.verbose) {
                    log('[D] Appending additional item: ' + obj.name);
                }
                newCollection.push(obj);

            } else if (typeof obj === 'string') {
                if (exports.settings.verbose) {
                    log('[D] Appending wikitext: ' + obj);
                }
                newCollection.push(obj);
            }

        }

        return newCollection;

    } else {
        log('[E] No valid form schema given!');
        log('[i] The applyForm() helper function can only be used for mobo projects.');
        log('[i] mobo has to be run at least once successfully in order to access the mobo registry');
        return objCollection;
    }
};

exports.findInCollection = function(collection, name) {

    var results = [];

    for (var i = 0; i < collection.length; i++) {
        var obj = collection[i];
        if (obj.name && obj.name === name) {
            results.push(obj);
        }
    }

    return results;

};