Alien-Web-HalBrowser

 view release on metacpan or  search on metacpan

share/vendor/js/uritemplates.js  view on Meta::CPAN

    }
    return base;
}

/**
 * Create a runtime cache around retrieved values from the context.
 * This allows for dynamic (function) results to be kept the same for multiple 
 * occuring expansions within one template.
 * Note: Uses key-value tupples to be able to cache null values as well.
 */
 //TODO move this into prep-processing
function CachingContext(context) {
    this.raw = context;
    this.cache = {};
}
CachingContext.prototype.get = function(key) {
    var val = this.lookupRaw(key);
    var result = val;
    
    if (isFunction(val)) { // check function-result-cache
        var tupple = this.cache[key];
        if (tupple !== null && tupple !== undefined) { 
            result = tupple.val;
        } else {
            result = val(this.raw);
            this.cache[key] = {key: key, val: result}; 
            // NOTE: by storing tupples we make sure a null return is validly consistent too in expansions
        }
    }
    return result;
};

CachingContext.prototype.lookupRaw = function(key) {
    return CachingContext.lookup(this, this.raw, key);
};

CachingContext.lookup = function(me, context, key) {
    var result = context[key];
    if (result !== undefined) {
        return result;
    } else {
        var keyparts = key.split('.');
        var i = 0, keysplits = keyparts.length - 1;
        for (i = 0; i<keysplits; i++) {
            var leadKey = keyparts.slice(0, keysplits - i).join('.');
            var trailKey = keyparts.slice(-i-1).join('.');
            var leadContext = context[leadKey];
            if (leadContext !== undefined) {
                return CachingContext.lookup(me, leadContext, trailKey);
            }
        }
        return undefined;
    }
};


function UriTemplate(set) {
    this.set = set;
}

UriTemplate.prototype.expand = function(context) {
    var cache = new CachingContext(context);
    var res = "";
    var i = 0, cnt = this.set.length;
    for (i = 0; i<cnt; i++ ) {
        res += this.set[i].expand(cache);
    }
    return res;
};

//TODO: change since draft-0.6 about characters in literals
/* extract:
The characters outside of expressions in a URI Template string are intended to be copied literally to the URI-reference if the character is allowed in a URI (reserved / unreserved / pct-encoded) or, if not allowed, copied to the URI-reference in its ...
*/
function Literal(txt ) {
    this.txt = txt;
}

Literal.prototype.expand = function() {
    return this.txt;
};



var RESERVEDCHARS_RE = new RegExp("[:/?#\\[\\]@!$&()*+,;=']","g");
function encodeNormal(val) {
    return encodeURIComponent(val).replace(RESERVEDCHARS_RE, function(s) {return escape(s);} );
}

//var SELECTEDCHARS_RE = new RegExp("[]","g");
function encodeReserved(val) {
    //return encodeURI(val).replace(SELECTEDCHARS_RE, function(s) {return escape(s)} );
    return encodeURI(val); // no need for additional replace if selected-chars is empty
}


function addUnNamed(name, key, val) {
    return key + (key.length > 0 ? "=" : "") + val;
}

function addNamed(name, key, val, noName) {
    noName = noName || false;
    if (noName) { name = ""; }
    
    if (!key || key.length === 0)  {
        key = name;
    }
    return key + (key.length > 0 ? "=" : "") + val;
}

function addLabeled(name, key, val, noName) {
    noName = noName || false;
    if (noName) { name = ""; }
    
    if (!key || key.length === 0)  {
        key = name;
    }
    return key + (key.length > 0 && val ? "=" : "") + val;
}


var simpleConf = { 
    prefix : "",     joiner : ",",     encode : encodeNormal,    builder : addUnNamed
};
var reservedConf = { 
    prefix : "",     joiner : ",",     encode : encodeReserved,  builder : addUnNamed
};
var fragmentConf = { 
    prefix : "#",    joiner : ",",     encode : encodeReserved,  builder : addUnNamed
};
var pathParamConf = { 
    prefix : ";",    joiner : ";",     encode : encodeNormal,    builder : addLabeled
};
var formParamConf = { 
    prefix : "?",    joiner : "&",     encode : encodeNormal,    builder : addNamed
};
var formContinueConf = { 
    prefix : "&",    joiner : "&",     encode : encodeNormal,    builder : addNamed
};
var pathHierarchyConf = { 
    prefix : "/",    joiner : "/",     encode : encodeNormal,    builder : addUnNamed
};
var labelConf = { 
    prefix : ".",    joiner : ".",     encode : encodeNormal,    builder : addUnNamed
};


function Expression(conf, vars ) {
    extend(this, conf);
    this.vars = vars;
}

Expression.build = function(ops, vars) {
    var conf;
    switch(ops) {
        case ''  : conf = simpleConf; break;
        case '+' : conf = reservedConf; break;
        case '#' : conf = fragmentConf; break;
        case ';' : conf = pathParamConf; break;
        case '?' : conf = formParamConf; break;
        case '&' : conf = formContinueConf; break;
        case '/' : conf = pathHierarchyConf; break;
        case '.' : conf = labelConf; break;
        default  : throw "Unexpected operator: '"+ops+"'"; 
    }
    return new Expression(conf, vars);
};

Expression.prototype.expand = function(context) {
    var joiner = this.prefix;
    var nextjoiner = this.joiner;
    var buildSegment = this.builder;
    var res = "";
    var i = 0, cnt = this.vars.length;
    
    for (i = 0 ; i< cnt; i++) {
        var varspec = this.vars[i];
        varspec.addValues(context, this.encode, function(key, val, noName) {
            var segm = buildSegment(varspec.name, key, val, noName);
            if (segm !== null && segm !== undefined) {
                res += joiner + segm;
                joiner = nextjoiner;
            }
        });
    }
    return res;
};



var UNBOUND = {};

/** 
 * Helper class to help grow a string of (possibly encoded) parts until limit is reached
 */
function Buffer(limit) {
    this.str = "";
    if (limit === UNBOUND) {
        this.appender = Buffer.UnboundAppend;
    } else {
        this.len = 0;
        this.limit = limit; 
        this.appender = Buffer.BoundAppend;
    }
}

Buffer.prototype.append = function(part, encoder) {
    return this.appender(this, part, encoder);
};

Buffer.UnboundAppend = function(me, part, encoder) {
    part = encoder ? encoder(part) : part;
    me.str += part;
    return me;
};

Buffer.BoundAppend = function(me, part, encoder) {
    part = part.substring(0, me.limit - me.len);
    me.len += part.length;
    
    part = encoder ? encoder(part) : part;
    me.str += part;
    return me;
};


function arrayToString(arr, encoder, maxLength) {
    var buffer = new Buffer(maxLength);    
    var joiner = "";



( run in 0.834 second using v1.01-cache-2.11-cpan-5b529ec07f3 )