@luminati-io/luminati-proxy
Version:
A configurable local proxy for luminati.io
238 lines (232 loc) • 7.39 kB
JavaScript
// LICENSE_CODE ZON ISC
; /*zlint node, br*/
(function(){
var define;
var is_node_ff = typeof module=='object' && module.exports;
if (!is_node_ff)
define = self.define;
else
define = require('./require_node.js').define(module, '../');
define(['/util/escape.js', '/util/util.js'], function(zescape, zutil){
var E = {};
E.glob_to_regex_str = function(glob){
return '^('
+glob.replace(/(\?|\*\*|\*)|([^?*]+)/g, function(m){
return m=='?' ? '[^/]' : m=='**' ? '.*' : m=='*' ? '[^/]*' :
zescape.regex(m); })
+')$';
};
E.glob_to_regex = function(glob){
return new RegExp(E.glob_to_regex_str(glob)); };
E.glob_fn = function(glob){
var re = E.glob_to_regex(glob);
return function(s){ return re.test(s); };
};
E.glob = function(glob, value){ return E.glob_fn(glob)(value); };
function eat_group(arr, start){
for (var c = 0, i = start; i < arr.length; i++)
{
if (arr[i].depth)
c += arr[i].depth;
if (!c)
return arr.splice(start, i-start+1).slice(1, -1);
}
throw new Error('unbalanced group');
}
function parse_arr_to_tree(arr, join){
function is_join(el){ return el.join && Object.keys(el).length==1; }
function clean(el){
if (!Array.isArray(el.elm))
delete el.join;
return el;
}
function pass(fn){
for (var i = 0; i < arr.length; i++)
{
var change;
if (change = fn(arr[i], arr[i+1], i))
i += change;
}
}
pass(function(el, next, i){
if (el.depth)
arr.splice(i, 0, parse_arr_to_tree(eat_group(arr, i), join));
});
pass(function(el, next, i){
if (el.fn && !el.elm)
el.elm = arr.splice(i+1, 1)[0];
});
pass(function(el, next, i){
if (is_join(el))
{
arr[i-1] = {join: el.join, elm: [arr[i-1], next].map(clean)};
arr.splice(i, 2);
return -1;
}
if (next && next.join=='&&' && !is_join(next))
{
arr[i] = {join: '&&', elm: [el, next].map(clean)};
arr.splice(i+1, 1);
}
});
if (arr.length<=1)
return arr[0];
return {join: join,
elm: [arr[0], parse_arr_to_tree(arr.slice(1), join), ].map(clean)};
}
E.match_parse = function(filter, opt){
var res = [], o = {s: filter}, cmp = [], match, i, _plugin;
var eat_token = zescape.parse.eat_token;
opt = opt||{};
var plugin = opt.plugin||[];
var join = opt.join||'||'; // default join operator
var logical = opt.logical===undefined || opt.logical;
token:
while (o.s.length)
{
if (opt.eat_white!==false && eat_token(o, /^\s+/))
continue;
for (i=0; i<plugin.length; i++)
{
_plugin = plugin[i];
if (match = eat_token(o, _plugin.re))
{
cmp.push({plugin: _plugin, m: match});
continue token;
}
}
if (match = eat_token(o, /^\/((\\.|[^\\/])+)\/([i]?)(\s|$)/))
{
cmp.push({re: match[1], re_opt: match[3]});
continue;
}
if (match = eat_token(o, /^\S+/))
{
var m = match[0], l;
var _logical = {'&&': {join: '&&'}, '||': {join: '||'},
'!': {fn: '!'}, '+': {join: '||'},
'-': {fn: '!', join: '&&', wrap_join: true},
'(': {fn: '(', depth: 1},
')': {fn: ')', depth: -1, join: ''}};
if (logical && (l = _logical[m]))
{
if (l.wrap_join)
{
var depth = 0;
for (i=cmp.length; i>=0 && depth>=0; i--)
depth += -(l.depth||0);
i++;
if (i<cmp.length)
{
cmp.splice(i, 0, _logical['(']);
cmp.push(_logical[')']);
}
delete l.wrap_join;
}
cmp.push(l);
}
else if (opt.glob && /[\[\]*?{}]/.test(m))
{
cmp.push(opt.glob=='re' ?
{re: E.glob_to_regex_str(m)} : {glob: m});
}
else
cmp.push({eq: m});
continue;
}
E.match_last_error = new Error('invalid token '+o.s);
}
var have_val = false;
cmp.forEach(function(c){
var _join = have_val && join;
if (c.eq!==undefined || c.re!==undefined ||
c.glob!==undefined || c.plugin)
{
have_val = true;
}
else
{
if (c.join!==undefined)
_join = c.join;
have_val = false;
}
if (_join)
c.join = _join;
else
delete c.join;
});
return opt.tree ? parse_arr_to_tree(cmp, join) : cmp;
};
E.match_fn = function(filter, opt){
opt = opt||{};
var cmp = E.match_parse(filter, opt), func = 'return ', i;
for (i=0; i<cmp.length; i++)
{
var c = cmp[i];
if (c.join)
func += c.join+' ';
if (c.re!==undefined)
{
try {
var re = new RegExp(c.re, c.re_opt);
c = function(s){ return this.test(s); }.bind(re);
} catch(e){
c = function(){ return false; };
E.match_last_error = e;
}
}
else if (c.glob!==undefined)
c = E.glob_fn(c.glob);
else if (c.eq!==undefined)
c = function(s){ return s===this; }.bind(c.eq);
else if (c.plugin)
{
c = c.plugin.cmp ? c.plugin.cmp.bind(null, c.m) :
c.plugin.cmp_fn(c.m);
}
cmp[i] = c;
if (typeof c=='function')
func += 'cmp['+i+'](s, extra) ';
else if (c instanceof Object)
func += c.fn ? c.fn+' ' : '';
else
throw new Error();
}
if (!cmp.length)
func += 'false ';
func += ';';
return new Function(['cmp', 's', 'extra'], func).bind(null, cmp);
};
E.match = function(filter, value, opt){
return E.match_fn(filter, opt)(value, opt && opt.extra); };
E.cmp_norm = function(cmp){ return cmp>0 ? 1 : cmp<0 ? -1 : 0; };
// XXX: move to util.js, change name to non-string-related
E.strcmp = function(a, b){ return a>b ? 1 : a<b ? -1 : 0; };
E.strverscmp = function(a, b){
var _a, _b, diff, skip_digit = 0;
for (_a=0, _b=0; _a<a.length && _b<b.length; _a++, _b++)
{
if (a[_a]==b[_b] && !zutil.isdigit(a[_b])) // fast-path
continue;
if (skip_digit)
skip_digit--;
if (zutil.isdigit(a[_a]) && zutil.isdigit(b[_b]))
{
var ma = a.substr(_a).match(/\d+/)[0];
var mb = b.substr(_b).match(/\d+/)[0];
if (diff = +ma - +mb)
return diff;
skip_digit = ma.length;
}
if (diff = a[_a].charCodeAt()-b[_b].charCodeAt())
return diff;
}
return a.length-b.length;
};
E.regexp_merge = function(a){
var re = [], i;
for (i=0; i<a.length; i++)
re.push(a[i] instanceof RegExp ? a[i].source : zescape.regex(''+a[i]));
return new RegExp('('+re.join(')|(')+')');
};
return E; }); }());