fossasia/loklak_webclient

View on GitHub
iframely/modules/tests-ui/utils.js

Summary

Maintainability
C
7 hrs
Test Coverage
var _ = require('underscore');
var FeedParser = require('feedparser');
var request = require('request');
var async = require('async');
var url = require('url');

var iframelyGetPluginData = require('../../lib/core').getPluginData;

var pluginLoader = require('../../lib/loader/pluginLoader');
var pluginUtils = require('../../lib/loader/utils');
var plugins = pluginLoader._plugins,
    DEFAULT_PARAMS = [].concat(pluginUtils.DEFAULT_PARAMS, pluginUtils.POST_PLUGIN_DEFAULT_PARAMS),
    PLUGIN_METHODS = pluginUtils.PLUGIN_METHODS;

exports.getPluginUnusedMethods = function(pluginId, debugData) {

    var usedMethods = getAllUsedMethods(debugData);
    var pluginMethods = findAllPluginMethods(pluginId, plugins);

    return {
        allMandatoryMethods: pluginMethods.mandatory,
        mandatory: _.difference(pluginMethods.mandatory, usedMethods),
        skipped: _.difference(pluginMethods.skipped, usedMethods)
    };
};

exports.getErrors = function(debugData) {

    var errors = [];

    debugData.allData.forEach(function(methodData) {
        if (methodData.error) {
            var methodId = methodData.method.pluginId + " - " + methodData.method.name;
            errors.push(methodId + ": " + methodData.error);
        }
    });

    if (errors.length) {
        return errors;
    } else {
        return null;
    }
};

var MAX_FEED_URLS = 5;

var fetchFeedUrls = exports.fetchFeedUrls = function(feedUrl, options, cb) {

    if (typeof options === "function") {
        cb = options;
        options = {};
    }

    var urls = [];

    var cbed = false;
    var _cb = function(error) {
        if (cbed) {
            return;
        }
        cbed = true;
        cb(error, urls);
    };

    request(feedUrl)
        .pipe(new FeedParser({addmeta: false}))
        .on('error', function(error) {
            _cb(error);
        })
        .on('readable', function () {
            var stream = this, item;
            while (item = stream.read()) {

                if (urls.length < MAX_FEED_URLS) {

                    var url = item.origlink || item.link;

                    if (options.getUrl) {
                        url = options.getUrl(url);
                    }

                    if (!url) {
                        return;
                    }

                    urls.push(url);

                    if (MAX_FEED_URLS == urls.length) {
                        _cb();
                    }
                }
            }
        })
        .on('end', function() {
            _cb();
        });
};

exports.fetchUrlsByPageOnFeed = function(pageWithFeed, otpions, cb) {

    if (typeof options === "function") {
        cb = options;
        options = {};
    }

    async.waterfall([

        function(cb) {
            iframelyGetPluginData(pageWithFeed, 'meta', cb);
        },

        function(meta, cb) {
            var alternate = meta.alternate;

            var feeds;

            if (alternate) {

                if (!(alternate instanceof Array)) {
                    alternate = [alternate];
                }

                feeds = alternate.filter(function(o) {
                    return o.href && (o.type == "application/atom+xml" || o.type == "application/rss+xml");
                });
            }

            if (feeds && feeds.length > 0) {

                cb(null, feeds[0].href, otpions);

            } else {
                cb("No feeds found on " + pageWithFeed);
            }
        },

        fetchFeedUrls

    ], cb);
};

exports.fetchUrlsByPageAndSelector = function(page, selector, options, cb) {

    if (typeof options === "function") {
        cb = options;
        options = {};
    }

    async.waterfall([

        function(cb) {
            iframelyGetPluginData(page, 'cheerio', cb);
        },

        function($, cb) {

            var $links = $(selector);

            var urls = [];
            $links.each(function() {
                if (urls.length < MAX_FEED_URLS) {
                    var href = $(this).attr("href");
                    if (href) {
                        var href = url.resolve(page, href);
                        if (urls.indexOf(href) == -1) {

                            if (options.getUrl) {
                                href = options.getUrl(href);
                            }

                            if (!href) {
                                return;
                            }

                            urls.push(href);
                        }
                    }
                }
            });

            if (urls.length) {
                cb(null, urls);
            } else {
                cb("No urls found on " + page + " using selector='" + selector + "'");
            }
        }
    ], cb);
};

function getAllUsedMethods(debugData) {

    var result = [];

    // Collect all meta sources.
    for(var metaKey in debugData.meta._sources) {
        findUsedMethods({findByMeta: metaKey}, debugData, result);
    }

    // Collect all links sources
    debugData.links.forEach(function(link) {
        findUsedMethods({link: link}, debugData, result);
    });

    // Collect duplicate links.
    findUsedMethods({findSkippedDuplicates: true}, debugData, result);

    return result;
}

function findAllPluginMethods(pluginId, plugins, result, skipped) {

    result = result || {
        mandatory: [],
        skipped: []
    };

    var plugin = plugins[pluginId];

    var skipMixins = [];
    var skipMethods = [];
    var tests = plugin.module.tests;
    tests && tests.forEach && tests.forEach(function(test) {
        if (test.skipMixins) {
            skipMixins = _.union(skipMixins, test.skipMixins);
        }
        if (test.skipMethods) {
            skipMethods = _.union(skipMethods, test.skipMethods);
        }
    });

    plugin.module.mixins && plugin.module.mixins.forEach(function(mixin) {

        if (!skipped && skipMixins.indexOf(mixin) == -1) {
            findAllPluginMethods(mixin, plugins, result);
        } else {
            findAllPluginMethods(mixin, plugins, result, true);
        }

    });

    PLUGIN_METHODS.forEach(function(method) {

        var methodId = pluginId + " - " + method;
        if (method in plugin.methods && result.mandatory.indexOf(methodId) == -1 && result.skipped.indexOf(methodId) == -1) {

            if (!skipped && skipMethods.indexOf(method) == -1) {
                result.mandatory.push(methodId);
            } else {
                result.skipped.push(methodId);
            }
        }
    });

    return result;
}

function findUsedMethods(options, debugData, result) {

    // Find debug data for specific link.

    result = result || [];

    debugData.allData.forEach(function(methodData) {

        if (!methodData.data) {
            return;
        }

        var resultData = methodData.data;
        if (!(resultData instanceof Array)) {
            resultData = [resultData];
        }

        resultData.forEach(function(l) {

            var good = false;
            if (options.link) {
                good = l.sourceId === options.link.sourceId;
            }

            if (options.findByMeta) {
                var pluginId = debugData.meta._sources[options.findByMeta];
                good = pluginId === methodData.method.pluginId
                        && methodData.method.name === 'getMeta'
                        && options.findByMeta in l;
            }

            if (options.findByData) {
                try {
                    good = _.intersection(_.keys(l), options.findByData).length > 0;
                } catch(ex) {
                    good = false;
                }
            }

            if (options.findSkippedDuplicates && l.error && l.error.indexOf && l.error.indexOf('duplication') > -1) {
                good = true
            }

            if (good) {

                var methodId = methodData.method.pluginId + " - " + methodData.method.name;

                var exists = result.indexOf(methodId) > -1;
                if (exists) {
                    return
                }

                result.push(methodId);

                var params = plugins[methodData.method.pluginId].methods[methodData.method.name];

                // Find parent data source.

                var findSourceForRequirements = _.difference(params, DEFAULT_PARAMS);

                if (findSourceForRequirements.length > 0) {
                    findUsedMethods({
                        findByData: findSourceForRequirements
                    }, debugData, result);
                }
            }
        });
    });

    return result;
}