angular2-rest-api
Version:
This is a REST api provider for angular for http actions request to server and instantiate models.
156 lines (155 loc) • 6.67 kB
JavaScript
;
class Helper {
/**
* Copy instance with their methods
*/
static copyInstances(target, ...sources) {
sources.forEach(source => {
Object.defineProperties(target, Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {}));
});
return target;
}
/**
* We need our custom method because encodeURIComponent is too aggressive and doesn't follow
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
* (pchar) allowed in path segments:
* segment = *pchar
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
* pct-encoded = "%" HEXDIG HEXDIG
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
*/
static encodeUriSegment(val) {
return Helper.encodeUriQuery(val, true).
replace(/%26/gi, '&').
replace(/%3D/gi, '=').
replace(/%2B/gi, '+');
}
/**
* This method is intended for encoding *key* or *value* parts of query component. We need a
* custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
* have to be encoded per http://tools.ietf.org/html/rfc3986:
* query = *( pchar / "/" / "?" )
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* pct-encoded = "%" HEXDIG HEXDIG
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
*/
static encodeUriQuery(val, pctEncodeSpaces) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}
static *entries(obj) {
if (obj) {
for (let key of Object.keys(obj)) {
yield [key, obj[key]];
}
}
}
// Helper functions and regex to lookup a dotted path on an object
// stopping at undefined/null. The path must be composed of ASCII
// identifiers (just like $parse)
static isValidDottedPath(path) {
let MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;
return (path != null && path !== '' && path !== 'hasOwnProperty' &&
MEMBER_NAME_REGEX.test('.' + path));
}
static lookupDottedPath(obj, path) {
if (!Helper.isValidDottedPath(path)) {
//noinspection TypeScriptValidateTypes
throw Error('badmember', 'Dotted member path "@{0}" is invalid.', path);
}
var keys = path.split('.');
for (var i = 0, ii = keys.length; i < ii && typeof obj !== 'undefined'; i++) {
var key = keys[i];
obj = (obj !== null) ? obj[key] : undefined;
}
return obj;
}
static extractParams(data, actionParams) {
var ids = {};
for (let [key, value] of Helper.entries(actionParams)) {
if (value && typeof value === 'function') {
value = value();
}
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
Helper.lookupDottedPath(data, value.substr(1)) : value;
}
return ids;
}
static setUrlParams(data, params, actionUrl) {
let protocolAndDomain = '', urlParams = {}, url = actionUrl, PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/, val, encodedVal;
url.split(/\W/).forEach(function (param) {
if (param === 'hasOwnProperty') {
//noinspection TypeScriptValidateTypes
throw Error('badname', "hasOwnProperty is not a valid parameter name.");
}
if (!(new RegExp("^\\d+$").test(param)) && param &&
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
let isQueryParamValue = (new RegExp("\\?.*=:" + param + "(?:\\W|$)")).test(url);
urlParams[param] = {
isQueryParamValue: isQueryParamValue
};
if (!params[param] && !isQueryParamValue) {
params[param] = '@' + param;
}
}
});
url = url.replace(/\\:/g, ':');
url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function (match) {
protocolAndDomain = match;
return '';
});
params = Helper.extractParams(data, params) || {};
for (let [urlParam, paramInfo] of Helper.entries(urlParams)) {
val = params.hasOwnProperty(urlParam) ? params[urlParam] : '';
if (typeof val !== 'undefined' && val !== null) {
console.log(paramInfo);
console.log(urlParam);
if (paramInfo.isQueryParamValue) {
encodedVal = Helper.encodeUriQuery(val, true);
}
else {
encodedVal = Helper.encodeUriSegment(val);
}
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function (match, p1) {
return encodedVal + p1;
});
}
else {
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function (match, leadingSlashes, tail) {
if (tail.charAt(0) == '/') {
return tail;
}
else {
return leadingSlashes + tail;
}
});
}
}
url = url.replace(/\/+$/, '') || '/';
// then replace collapse `/.` if found in the last URL path segment before the query
// E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
// replace escaped `/\.` with `/.`
let compiledUrl = protocolAndDomain + url.replace(/\/\\\./, '/.');
// set other get params
for (let [key, value] of Helper.entries(params)) {
if (!urlParams[key]) {
compiledUrl += (compiledUrl.indexOf("?") < 0 ? "?" : "&") + key + "=" + value;
}
}
return compiledUrl;
}
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Helper;