all files / umd/ url-builder.js

100% Statements 71/71
100% Branches 54/54
100% Functions 7/7
100% Lines 71/71
1 statement, 4 branches Ignored     
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219                                               40×                       48× 48× 48× 48× 48×   48×   48× 48×     48× 45×     48× 94×     94×           93× 93×     93×               86× 65×                 21×   13× 13×         94×       48×                         48×                       48×                                   13× 13×   13× 10× 10×                                         93×   93×   93× 93×   20×         93×     93× 54×     93×        
(function (global, factory) {
    'use strict';
 
    var built = factory(global);
 
    /* istanbul ignore else */
    Eif (typeof module === 'object' && module) {
        module.exports = built;
    }
 
    /* istanbul ignore next */
    Iif (typeof define === 'function' && define.amd) {
        define(factory);
    }
 
    global.URLBuilder = built;
}(typeof global !== 'undefined' ? global : /* istanbul ignore next */ this, function (global) {
 
    'use strict';
 
// External protocols regex, supports:
// "http", "https", "//" and "www."
var REGEX_EXTERNAL_PROTOCOLS = /^https?:\/\/|\/\/|www\./;
 
 
/**
 * Creates an instance of URLBuilder class.
 *
 * @constructor
 * @param {object} - instance of {@link ConfigParser} object.
 */
function URLBuilder(configParser) {
    this._configParser = configParser;
}
 
URLBuilder.prototype = {
    constructor: URLBuilder,
 
    /**
     * Returns a list of URLs from provided list of modules.
     *
     * @param {array} modules List of modules for which URLs should be created.
     * @return {array} List of URLs.
     */
    build: function (modules) {
        var bufferAbsoluteURL = [];
        var bufferRelativeURL = [];
        var modulesAbsoluteURL = [];
        var modulesRelativeURL = [];
        var result = [];
 
        var config = this._configParser.getConfig();
 
        var basePath = config.basePath || '';
        var registeredModules = this._configParser.getModules();
 
        /* istanbul ignore else */
        if (basePath.length && basePath.charAt(basePath.length - 1) !== '/') {
            basePath += '/';
        }
 
        for (var i = 0; i < modules.length; i++) {
            var module = registeredModules[modules[i]];
 
            // If module has fullPath, individual URL have to be created.
            if (module.fullPath) {
                result.push({
                    modules: [module.name],
                    url: module.fullPath
                });
 
            } else {
                var path = this._getModulePath(module);
                var absolutePath = path.indexOf('/') === 0;
 
                // If the URL starts with external protocol, individual URL shall be created.
                if (REGEX_EXTERNAL_PROTOCOLS.test(path)) {
                    result.push({
                        modules: [module.name],
                        url: path
                    });
 
                // If combine is disabled, or the module is an anonymous one,
                // create an individual URL based on the config URL and module's path.
                // If the module's path starts with "/", do not include basePath in the URL.
                } else if (!config.combine || module.anonymous) {
                    result.push({
                        modules: [module.name],
                        url: config.url + (absolutePath ? '' : basePath) + path
                    });
 
                } else {
                    // If combine is true, this is not an anonymous module and the module does not have full path.
                    // The module will be collected in a buffer to be loaded among with other modules from combo loader.
                    // The path will be stored in different buffer depending on the fact if it is absolute URL or not.
                    if (absolutePath) {
                        bufferAbsoluteURL.push(path);
                        modulesAbsoluteURL.push(module.name);
                    } else {
                        bufferRelativeURL.push(path);
                        modulesRelativeURL.push(module.name);
                    }
                }
            }
 
            module.requested = true;
        }
 
        // Add to the result all modules, which have to be combined.
        if (bufferRelativeURL.length) {
            result = result.concat(
                this._generateBufferURLs(
                    modulesRelativeURL,
                    bufferRelativeURL,
                    {
                        basePath: basePath,
                        url: config.url,
                        urlMaxLength: config.urlMaxLength
                    }
                )
            );
            bufferRelativeURL.length = 0;
        }
 
        if (bufferAbsoluteURL.length) {
            result = result.concat(
                this._generateBufferURLs(
                    modulesAbsoluteURL,
                    bufferAbsoluteURL,
                    {
                        url: config.url,
                        urlMaxLength: config.urlMaxLength
                    }
                )
            );
            bufferAbsoluteURL.length = 0;
        }
 
        return result;
    },
 
    /**
     * Generate the appropriate set of URLs based on the list of
     * required modules and the maximum allowed URL length
     *
     * @param {Array<String>} modules Array of module names
     * @param {Array<String>} urls Array of module URLs
     * @param {Object} config Configuration object containing URL, basePath and urlMaxLength
     * @return {Array<Object>} Resulting array of {modules, url} objects
     */
    _generateBufferURLs: function(modules, urls, config) {
        var i;
        var basePath = config.basePath || '';
        var result = [];
        var urlMaxLength = config.urlMaxLength || 2000;
 
        var urlResult = {
            modules: [modules[0]],
            url: config.url + basePath + urls[0]
        };
 
        for (i = 1; i < urls.length; i++) {
            var module = modules[i];
            var path = urls[i];
 
            if ((urlResult.url.length + basePath.length + path.length + 1) < urlMaxLength) {
                urlResult.modules.push(module);
                urlResult.url += '&' + basePath + path;
            } else {
                result.push(urlResult);
 
                urlResult = {
                    modules: [module],
                    url: config.url + basePath + path
                };
            }
        }
 
        result.push(urlResult);
 
        return result;
    },
 
    /**
     * Returns the path for a module. If module has property path, it will be returned directly. Otherwise,
     * the name of module will be used and extension .js will be added to module name if omitted.
     *
     * @protected
     * @param {object} module The module which path should be returned.
     * @return {string} Module path.
     */
    _getModulePath: function (module) {
        var path = module.path || module.name;
 
        var paths = this._configParser.getConfig().paths || {};
 
        var found = false;
        Object.keys(paths).forEach(function(item) {
            /* istanbul ignore else */
            if (path === item || path.indexOf(item + '/') === 0) {
                path = paths[item] + path.substring(item.length);
            }
        });
 
        /* istanbul ignore else */
        if(!found && typeof paths['*'] === 'function') {
            path = paths['*'](path);
        }
 
        if (!REGEX_EXTERNAL_PROTOCOLS.test(path) && path.indexOf('.js') !== path.length - 3) {
            path += '.js';
        }
 
        return path;
    }
};
 
    return URLBuilder;
}));