web-dev-server
Version:
Node.js simple http server for common development or training purposes.
404 lines • 16.5 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.StringHelper = void 0;
var ObjectHelper_1 = require("./ObjectHelper");
var Collection_1 = require("./StringHelpers/QueryString/Collection");
var StringHelper = /** @class */ (function () {
function StringHelper() {
}
StringHelper.Trim = function (str, chars) {
var ch, newStr = '';
for (var a = 0, b = chars.length; a < b; a++) {
ch = chars.charAt(a);
for (var i = 0, l = str.length; i < l; i += 1) {
if (str.charAt(i) == ch) {
newStr = str.substr(i + 1);
}
else {
newStr = str.substr(i);
break;
}
}
str = newStr;
for (var i = str.length - 1; i > -1; i -= 1) {
if (str.charAt(i) == ch) {
newStr = str.substring(0, i);
}
else {
newStr = str.substring(0, i + 1);
break;
}
}
}
return newStr;
};
StringHelper.TrimLeft = function (str, chars) {
var ch, newStr = '';
for (var a = 0, b = chars.length; a < b; a++) {
ch = chars.charAt(a);
for (var i = 0, l = str.length; i < l; i += 1) {
if (str.charAt(i) == ch) {
newStr = str.substr(i + 1);
}
else {
newStr = str.substr(i);
break;
}
}
}
return newStr;
};
StringHelper.TrimRight = function (str, chars) {
var ch, newStr = '';
for (var a = 0, b = chars.length; a < b; a++) {
ch = chars.charAt(a);
for (var i = str.length - 1; i > -1; i -= 1) {
if (str.charAt(i) == ch) {
newStr = str.substring(0, i);
}
else {
newStr = str.substring(0, i + 1);
break;
}
}
}
return newStr;
};
StringHelper.DecodeUri = function (str) {
var result = str;
try {
result = decodeURIComponent(str);
}
catch (e) {
var index = 0, lastIndex = 0, safePart;
while (true) {
if (index >= result.length)
break;
safePart = result.substr(index);
if (!safePart.match(/[\%]([0-9]{2,})/g))
break;
safePart = safePart.replace(/[\%]([0-9]{2,})/g, function (wholeMatch, groupMatch, indexLocal) {
var result = wholeMatch;
try {
result = decodeURIComponent(result);
index = indexLocal + result.length;
}
catch (e) {
index = indexLocal + wholeMatch.length;
}
return result;
});
result = result.substr(0, lastIndex) + safePart;
lastIndex = index;
}
}
return result;
};
StringHelper.Strtr = function (str, dic) {
var makeToken = function (inx) { return "{{###~" + inx + "~###}}"; }, tokens = Object.keys(dic).map(function (key, inx) { return ({
key: key,
val: dic[key],
token: makeToken(inx)
}); }), tokenizedStr = tokens.reduce(function (carry, entry) { return carry ? carry.replace(entry.key, entry.token) : carry; }, str);
return tokens.reduce(function (carry, entry) { return carry ? carry.replace(entry.token, entry.val) : carry; }, tokenizedStr);
};
/**
* Convert special characters to HTML entities except ampersand `&`.
* @see http://php.net/manual/en/function.htmlspecialchars.php
* @param str
*/
StringHelper.HtmlSpecialChars = function (str, includeAmpersand) {
if (includeAmpersand === void 0) { includeAmpersand = true; }
if (includeAmpersand)
return StringHelper.Strtr(str, this.HTML_SPECIAL_CHARS);
return StringHelper.Strtr(str, this.HTML_SPECIAL_CHARS_WITHOUT_AMP);
};
StringHelper.HtmlEntitiesEncode = function (rawStr) {
return rawStr.replace(/[\u00A0-\u9999<>\&]/gim, function (i) {
return '&#' + i.charCodeAt(0) + ';';
});
};
StringHelper.RawUrlDecode = function (str) {
return decodeURIComponent((str + '')
.replace(/%(?![\da-f]{2})/gi, function () {
// PHP tolerates poorly formed escape sequences
return '%25';
}));
};
StringHelper.QueryStringEncode = function (obj, encodeAmp) {
if (encodeAmp === void 0) { encodeAmp = false; }
var items = [];
this.encodeQueryStringRecursive('', [], obj, items, 0);
return items.join(encodeAmp ? '&' : '&');
};
StringHelper.encodeQueryStringRecursive = function (prefix, keys, value, items, level) {
var _this = this;
var result, keysClone, keyStr, objKeys, protoName;
if (ObjectHelper_1.ObjectHelper.IsPrimitiveType(value)) {
result = prefix;
if (keys.length > 0)
result += '[' + keys.join('][') + ']';
result += '=';
if (value != null)
result += encodeURIComponent(String(value));
items.push(result);
}
else if (value instanceof Map) {
value.forEach(function (valueLocal, keyLocal) {
keysClone = [].concat(keys);
keysClone.push(encodeURIComponent(keyLocal));
_this.encodeQueryStringRecursive(prefix, keysClone, valueLocal, items, level + 1);
});
}
else if (value instanceof Set) {
value.forEach(function (valueLocal) {
keysClone = [].concat(keys);
keysClone.push('');
_this.encodeQueryStringRecursive(prefix, keysClone, valueLocal, items, level + 1);
});
}
else {
protoName = ObjectHelper_1.ObjectHelper.RealTypeOf(value);
if (protoName.indexOf('Array') != -1) {
for (var i = 0, l = value['length']; i < l; i++) {
keysClone = [].concat(keys);
keysClone.push('');
this.encodeQueryStringRecursive(prefix, keysClone, value[i], items, level + 1);
}
}
else {
objKeys = Object.keys(value);
for (var i = 0, l = objKeys.length; i < l; i++) {
keyStr = objKeys[i];
keysClone = [].concat(keys);
if (level === 0) {
prefix = encodeURIComponent(keyStr);
}
else {
keysClone.push(encodeURIComponent(keyStr));
}
this.encodeQueryStringRecursive(prefix, keysClone, value[keyStr], items, level + 1);
}
}
}
};
StringHelper.QueryStringDecode = function (str, autoRetype) {
if (autoRetype === void 0) { autoRetype = false; }
var result = {}, collections = [], lastCollectionId = 0, lastLevel, itemsRaw, itemRaw, itemRawKey, itemRawValue, itemKeys, lastLevelObject;
// trim & from left and right and explode by &?
itemsRaw = this.queryStringDecodePrepareItems(str);
for (var i = 0, l = itemsRaw.length; i < l; i++) {
itemRaw = this.queryStringDecodeExplodeKeyValue(itemsRaw[i]);
itemRawKey = itemRaw[0];
itemRawValue = itemRaw[1];
// go to next point only if key is valid and if key doesn't start with `[` bracket:
if (!(itemRawKey.length > 0 && itemRawKey.charAt(0) !== '['))
continue;
itemKeys = this.queryStringDecodeItemKeys(itemRawKey);
// start to assign value into proper level
lastLevel = this.queryStringDecodeGetLastLevel(itemKeys, result, collections, lastCollectionId);
lastCollectionId = lastLevel.lastId;
lastLevelObject = lastLevel.level;
itemRawKey = lastLevel.key;
// assign value into proper level collection object:
if (autoRetype) {
lastLevelObject[itemRawKey] = this.queryStringDecodeRetypeValue(itemRawValue);
}
else {
lastLevelObject[itemRawKey] = itemRawValue;
}
}
return this.queryStringDecodeRetypeCollections(result, collections);
};
StringHelper.queryStringDecodePrepareItems = function (str) {
str = String(str).replace(/\+/g, '%20');
str = StringHelper.DecodeUri(str);
str = str
.replace(/^&/, '')
.replace(/&$/, '');
return str.split('&');
};
StringHelper.queryStringDecodeRetypeValue = function (itemRawValue) {
var itemValue;
if (itemRawValue.match(/^(true|false)$/g)) {
itemValue = itemRawValue === "true";
}
else if (itemRawValue.match(/^(null|undefined)$/g)) {
itemValue = itemRawValue === "null" ? null : undefined;
}
else if (itemRawValue.match(/^([eE0-9\+\-\.]+)$/g)) {
var matchedDots = itemRawValue.match(/\./g);
if (!matchedDots || (matchedDots && matchedDots.length < 2)) {
itemValue = parseFloat(itemRawValue);
if (isNaN(itemValue))
itemValue = itemRawValue;
}
else {
itemValue = itemRawValue;
}
}
else {
itemValue = itemRawValue;
}
return itemValue;
};
StringHelper.queryStringDecodeExplodeKeyValue = function (itemRaw) {
var itemRawKey, itemRawValue, strPos;
// explode by first `=`:
strPos = itemRaw.indexOf('=');
if (strPos == -1) {
itemRawKey = itemRaw;
itemRawValue = "true";
}
else {
itemRawKey = itemRaw.substr(0, strPos);
itemRawValue = itemRaw.substr(strPos + 1);
}
// trim key with ` ` from left:
while (itemRawKey.charAt(0) === ' ')
itemRawKey = itemRawKey.slice(1);
// trim key with ` ` from right:
while (itemRawKey.charAt(itemRawKey.length - 1) === ' ')
itemRawKey = itemRawKey.slice(0, itemRawKey.length - 1);
// discard everything after null char:
strPos = itemRawKey.indexOf('\x00');
if (strPos != -1)
itemRawKey = itemRawKey.slice(0, strPos);
return [itemRawKey, itemRawValue];
};
StringHelper.queryStringDecodeItemKeys = function (itemRawKey) {
var itemRawKeyLength = itemRawKey.length, itemKeys = [], beginPos, endPos, index = 0;
beginPos = itemRawKey.indexOf('[');
if (beginPos == -1) {
itemKeys = [itemRawKey];
}
else {
itemKeys.push(itemRawKey
.substr(0, beginPos)
.replace(/^['"]/, '')
.replace(/['"]$/, ''));
index = beginPos;
while (index < itemRawKeyLength) {
beginPos = itemRawKey.indexOf('[', index);
if (beginPos == -1)
break;
endPos = itemRawKey.indexOf(']', beginPos);
if (endPos == -1)
break;
itemKeys.push(itemRawKey
.substr(beginPos + 1, endPos - beginPos - 1)
.replace(/^['"]/, '')
.replace(/['"]$/, ''));
index = endPos + 1;
}
}
return itemKeys;
};
StringHelper.queryStringDecodeGetLastLevel = function (itemKeys, result, collections, lastCollectionId) {
var levelObject = result, itemCollection, levelObjectValue, lastLevelObject, itemRawKey;
for (var j = 0, k = itemKeys.length; j < k; j++) {
itemRawKey = itemKeys[j];
lastLevelObject = levelObject;
// if not root level and key is implicit:
if (j !== 0 &&
(itemRawKey === '' || itemRawKey === ' '))
itemRawKey = levelObject.length;
// if last key - break, because there will be value assignment only:
if (j + 1 === k)
break;
// if not last key - there will be another collection:
levelObjectValue = levelObject[itemRawKey];
if (levelObjectValue == null) {
// if there is no collection level yet:
itemCollection = new Collection_1.QueryStringCollection();
collections.push({
collection: itemCollection,
parent: levelObject,
key: itemRawKey,
level: j,
id: lastCollectionId++
});
levelObject[itemRawKey] = itemCollection;
levelObject = itemCollection;
}
else {
levelObject = levelObjectValue;
}
}
return {
level: lastLevelObject,
key: itemRawKey,
lastId: lastCollectionId
};
};
StringHelper.queryStringDecodeRetypeCollections = function (result, collections) {
// sort all collections reversly
var collectionItem;
collections.sort(function (a, b) {
var aLevel = a.level, bLevel = b.level;
if (aLevel == bLevel)
return b.id - a.id;
return bLevel - aLevel;
});
for (var i = 0, l = collections.length; i < l; i++) {
collectionItem = collections[i];
collectionItem.parent[collectionItem.key] = Object.getPrototypeOf(collectionItem.collection);
}
return result;
};
/**
* Recognize if given string is JSON or not without JSON parsing.
* @see https://www.ietf.org/rfc/rfc4627.txt
* @param jsonStr
* @return bool
*/
StringHelper.IsJsonString = function (jsonStr) {
var match = jsonStr
.replace(/"(\.|[^\\"])*"/g, '')
.match(/[^\,\:\{\}\[\]0-9\.\\\-\+Eaeflnr-u \n\r\t]/g);
return !Boolean(match && match.length > 0);
};
/**
* Recognize if given string is query string without parsing.
* It recognizes query strings like:
* - `key1=value1`
* - `key1=value1&`
* - `key1=value1&key2=value2`
* - `key1=value1&key2=value2&`
* - `key1=&key2=value2`
* - `key1=value&key2=`
* - `key1=value&key2=&key3=`
* ...
* @param jsonStr
*/
StringHelper.IsQueryString = function (queryStr) {
var queryStr = this.Trim(this.Trim(queryStr, '='), '&');
var apmsCount = queryStr.split('&').length - 1;
var equalsCount = queryStr.split('=').length - 1;
var firstAndLast = queryStr.substr(0, 1) + queryStr.substr(-1, 1);
if (firstAndLast === '{}' || firstAndLast === '[]')
return false; // most likely a JSON
if (apmsCount === 0 && equalsCount === 0)
return false; // there was `nothing`
if (equalsCount > 0)
equalsCount -= 1;
if (equalsCount === 0)
return true; // there was `key=value`
return apmsCount / equalsCount >= 1; // there was `key=&key=value`
};
StringHelper.HTML_SPECIAL_CHARS = {
'"': '"',
"'": ''',
'<': '<',
'>': '>',
'&': '&',
};
StringHelper.HTML_SPECIAL_CHARS_WITHOUT_AMP = {
'"': '"',
"'": ''',
'<': '<',
'>': '>',
};
return StringHelper;
}());
exports.StringHelper = StringHelper;
//# sourceMappingURL=StringHelper.js.map