happn-commons
Version:
254 lines (220 loc) • 7.65 kB
JavaScript
module.exports = {
/*
Shared between the browser client and the server and nodejs client
*/
prepareWildPath: function (path) {
//strips out duplicate sequential wildcards, ie simon***bishop -> simon*bishop
return path.replace(/(.)\1+/g, '*');
},
makeRe: function (pattern) {
return new RegExp('^' + this.escapeRegex(pattern).replace(/\\\*/g, '.*') + '$', 'i');
},
escapeRegex: function (str) {
if (typeof str !== 'string') throw new TypeError('Expected a string');
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
},
wildcardPreliminaryMatch: function (pattern, matchTo) {
// do an explicit check
if (pattern.indexOf('*') === -1) return pattern === matchTo;
const preparedPattern = pattern.replace(/(.)\1+/g, '*'); //strip out *** ****** and replace with *
if (preparedPattern === '*') return true;
// do a starts with check
if (!matchTo.startsWith(preparedPattern.split('*')[0])) return false;
return preparedPattern;
},
wildcardMatch: function (pattern, matchTo) {
if (Array.isArray(pattern)) {
for (let subPattern of pattern) {
if (this.wildcardMatch(subPattern, matchTo)) {
return true;
}
}
return false;
}
const preparedOrMatched = this.wildcardPreliminaryMatch(pattern, matchTo);
if (typeof preparedOrMatched === 'boolean') return preparedOrMatched; //we have a match result, return it
return this.makeRe(preparedOrMatched).test(matchTo);
},
addLeadingSlashIfNone: function (path) {
return path.startsWith('/') ? path : '/' + path;
},
stripLeadingSlashes: function (path) {
return path.replace(/^\//, '');
},
whilst: function (test, iterator, cb) {
cb = cb || noop;
if (!test()) return cb(null);
var _this = this;
_this.__attempts = 0;
var next = function (err, args) {
_this.__attempts++;
if (err) return cb(err, _this.__attempts);
if (test.apply(this, args)) return iterator(_this.__attempts, next);
cb.apply(null, [null].concat(args, _this.__attempts));
}.bind(_this);
iterator(_this.__attempts, next);
},
//taken from https://github.com/alessioalex/tiny-each-async
async: function (arr, parallelLimit, iteratorFn, cb) {
var pending = 0;
var index = 0;
var lastIndex = arr.length - 1;
var called = false;
var limit;
var callback;
var iterate;
if (typeof parallelLimit === 'number') {
limit = parallelLimit;
iterate = iteratorFn;
callback = cb || function noop() {};
} else {
iterate = parallelLimit;
callback = iteratorFn || function noop() {};
limit = arr.length;
}
if (!arr.length) {
return callback();
}
var iteratorLength = iterate.length;
var shouldCallNextIterator = function shouldCallNextIterator() {
return !called && pending < limit && index < lastIndex;
};
var iteratorCallback = function iteratorCallback(err) {
if (called) {
return;
}
pending--;
if (err || (index === lastIndex && !pending)) {
called = true;
callback(err);
} else if (shouldCallNextIterator()) {
processIterator(++index);
}
};
var processIterator = function processIterator() {
pending++;
var args =
iteratorLength === 2
? [arr[index], iteratorCallback]
: [arr[index], index, iteratorCallback];
iterate.apply(null, args);
if (shouldCallNextIterator()) {
processIterator(++index);
}
};
processIterator();
},
clone: function (obj) {
return JSON.parse(JSON.stringify(obj));
},
checkPath: function (path, action) {
if (typeof path !== 'string') throw new Error(`Bad path [${path}], must be a string`);
if (action === 'set' && path.indexOf('*') > -1)
throw new Error(
"Bad path, if the action is 'set' the path cannot contain the * wildcard character"
);
if (path.match(/^[a-zA-Z0-9/(){}+=&:%@._*\-\s]+$/) == null)
throw new Error(
'Bad path, can only contain characters a-z A-Z 0-9 / & + = : @ % * ( ) _ -, ie: factory1@I&J(western-cape)/plant1:conveyer_2/stats=true/capacity=10%/*'
);
},
computeiv: function (secret) {
if (typeof secret !== 'string')
throw new Error('secret must be a string and cannot be null or undefined');
if (secret.length !== 32) throw new Error('secret must be 32 chars long');
var iv = '';
for (let x = 0; x < 32; x = x + 2) iv += secret[x];
return iv;
},
stringContainsAny: function (str, ...items) {
var re = new RegExp(items.join('|'));
return re.test(str);
},
removeLast: function (str, last) {
if (
!str || //null undefined or empty
!str.substring || //not a string
!last || //last is null undefined or empty
str[str.length - 1] !== last
)
//string doesnt end with specified last character
return str;
return str.substring(0, str.length - 1);
},
asyncCallback: function () {
var fn = arguments[0].bind.apply(arguments[0], Array.from(arguments));
if (setImmediate) return setImmediate(fn);
setTimeout(fn, 0);
},
wrapImmediate: function (fn, timeout) {
return function () {
if (timeout) return setTimeout(fn.bind(this), timeout, ...arguments);
if (setImmediate) {
setImmediate(fn.bind(this), ...arguments);
return;
}
setTimeout(fn.bind(this), ...arguments);
};
},
isPromise: function (obj) {
return (
!!obj &&
(typeof obj === 'object' || typeof obj === 'function') &&
typeof obj.then === 'function'
);
},
maybePromisify: function (originalFunction, opts) {
if (originalFunction == null) {
throw new Error('attempt to promisify a null function');
}
return function () {
var args = Array.prototype.slice.call(arguments);
var _this = this;
if (opts && opts.unshift) args.unshift(opts.unshift);
if (args[args.length - 1] == null) args.splice(args.length - 1);
// No promisify if last passed arg is function (ie callback)
if (typeof args[args.length - 1] === 'function') {
return originalFunction.apply(this, args);
}
return new Promise(function (resolve, reject) {
// push false callback into arguments
args.push(function (error, result, more) {
if (error) return reject(error);
if (more) {
var args = Array.prototype.slice.call(arguments);
args.shift(); // toss undefined error
return resolve(args); // resolve array of args passed to callback
}
return resolve(result);
});
try {
return originalFunction.apply(_this, args);
} catch (error) {
return reject(error);
}
});
};
},
promisify: function (fn) {
// MIT License, - thanks to paulmillr.com
if (typeof fn !== 'function') throw new TypeError('micro-promisify must receive a function');
return Object.defineProperties(
function () {
var _this = this;
for (var args = new Array(arguments.length), i = 0; i < args.length; ++i)
args[i] = arguments[i]; // git.io/vk55A
return new Promise(function (resolve, reject) {
args.push(function (error, result) {
error == null ? resolve(result) : reject(error);
});
fn.apply(_this, args);
});
},
{
length: { value: Math.max(0, fn.length - 1) },
name: { value: fn.name },
}
);
},
};
function noop() {}