UNPKG

web-dev-server

Version:

Node.js simple http server for common development or training purposes.

404 lines 16.5 kB
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 ? '&amp;' : '&'); }; 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 = { '"': '&quot;', "'": '&apos;', '<': '&lt;', '>': '&gt;', '&': '&amp;', }; StringHelper.HTML_SPECIAL_CHARS_WITHOUT_AMP = { '"': '&quot;', "'": '&apos;', '<': '&lt;', '>': '&gt;', }; return StringHelper; }()); exports.StringHelper = StringHelper; //# sourceMappingURL=StringHelper.js.map