sebastian-software/core

View on GitHub
source/class/jasy/Env.js

Summary

Maintainability
A
1 hr
Test Coverage
/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2010-2012 Zynga Inc.
  Copyright 2012-2014 Sebastian Werner
==================================================================================================
*/

"use strict";

(function(undef)
{
    /** {=Map} Map of selected field values */
    var permutated = {};

    /** {=Map} Internal database of available fields with their current values */
    var selected = {};

    /** {=String} Computed checksum */
    var checksum = null;

    // Combines all passed arguments into a valid URL
    var joinUrl = function(all) {
        var url;
        for (var i=0, ii=all.length; i<ii; i++) {
            var part = all[i];
            if (part) {
                if (!url) {
                    url = part;
                } else {
                    url += "/" + part;
                }
            }
        }
        return url;
    };

    // At this level Array.prototype.indexOf might not be support, so we implement a custom logic for a contains check
    var contains = function(array, value)
    {
        for (var i=0, l=array.length; i<l; i++)
        {
            if (array[i] == value) {
                return true;
            }
        }
    };

    /**
     * {var} Returns the value of the field with the given @name {String}.
     */
    var getValue = function(name)
    {
        if (!(name in selected)) {
            throw new Error("[jasy.Env]: Field " + name + " is not available (yet)!");
        }

        return selected[name];
    };


    /**
     * This class is the client-side representation for the permutation features of
     * Jasy and supports features like auto-selecting builds based on specific feature sets.
     */
    core.Module("jasy.Env",
    {
        /** {=Map} Map of all fields with their values. */
        SELECTED : selected,

        /** {=Map} Map of all permutated fields which are relevant for checksum compution */
        PERMUTATED : permutated,


        /**
         * Configure environment data dynamically via setting a field @name {String} and its @value {var}.
         */
        define : function(name, value) {
            selected[name] = value;
        },


        /**
         * Adds the given @field {Array} as exported by Jasy.
         */
        addField : function(field)
        {
            // possible variants
            // 1: name, 1, test, [val1, val2]
            // 2: name, 2, value
            // 3: name, 3, test, default (not permutated)
            // 4: name, 4, value (not permutated)

            var name = field[0];
            var type = field[1];
            if (type == 1 || type == 3)
            {
                var test = field[2];
                if (!test) {
                    throw new Error("[jasy.Env]: Detection class for field " + name + " is not available!");
                }

                var value = "VALUE" in test ? test.VALUE : test.get(name);
                var third = field[3];

                // Fallback to first value if test results in unsupported value
                if (type == 1 && !contains(third, value)) {
                    value = third[0];
                }

                // Fill in missing value with default
                else if (type == 3 && value == null) {
                    value = third;
                }
            }
            else
            {
                // In cases with no test, we don't have an array of fields but just a value
                value = field[2];
            }

            // Add all fields - even static ones - to the selected data
            selected[name] = value;

            // Only add permutated fields to the permutated map.
            if (type == 1 || type == 2)
            {
                permutated[name] = value;
                checksum = null;
            }
        },


        /**
         * {String} Returns the SHA1/Base62 checksum of the current permutated field set and build revision.
         * This checksum is compatatible with the Jasy approach for computing it.
         */
        getId : function()
        {
            if (checksum != null) {
                return checksum;
            }

            var names = [];
            for (var name in permutated) {
                names.push(name);
            }

            names.sort();

            var list = [];
            for (var i=0, l=names.length; i<l; i++)
            {
                var name = names[i];
                list.push(name + ":" + permutated[name]);
            }

            var key = list.join(";");
            var rev = selected["jasy.build.rev"];
            if (rev) {
                key += "@" + rev;
            }

            return core.util.Base62.encodeArrayToString(core.crypt.SHA1.checksumAsByteArray(key));
        },


        /**
         * Used by Jasy to inject @fields {Array} data
         *
         * Deprecated!
         */
        setFields : function(fields)
        {
            for (var i=0, l=fields.length; i<l; i++) {
                this.addField(fields[i]);
            }
        },


        /**
         * Returns a fully qualified URL of the given @part {String} content
         * for the given @type {String}.
         */
        getPartUrl : function(part, type)
        {
            var folder = selected["jasy.folder." + type];
            if (folder == null) {
                throw new Error("Unsupported type for URL generator: " + type);
            }

            return joinUrl([
                jasy.Env.getValue("jasy.url"),
                selected["jasy.folder." + type],
                part + "-" + jasy.Env.getId() + "." + type
            ]);
        },


        getValue : getValue,


        /**
         * {Boolean} Whether the field with the given @name {String} was set to the given @value {var?true}.
         *
         * Boolean fields could also be checked without a given value as the value
         * defaults to `true`.
         */
        isSet : function(name, value)
        {
            // Fallback to value of true
            if (value === undef) {
                value = true;
            }

            // Explicit use of normal equal here to not differ between numbers and strings etc.
            return getValue(name) == value;
        },


        /**
         * {var} Selects and returns the current value of the field with the given
         * @name {String} from the given @map {Map}.
         */
        select: function(name, map) {
            return map[getValue(name)];
        }
    });
})();