UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

322 lines 12.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.endsWith = endsWith; exports.startsWith = startsWith; exports.trim = trim; exports.trimEnd = trimEnd; exports.trimStart = trimStart; exports.splice = splice; exports.padRight = padRight; exports.padLeft = padLeft; exports.GetTokens = GetTokens; exports.ReplaceTokens = ReplaceTokens; exports.ReplaceTokensInDictionary = ReplaceTokensInDictionary; exports.normalizeGuid = normalizeGuid; exports.isEmptyGuid = isEmptyGuid; exports.escapeRegExp = escapeRegExp; exports.isValidDomainLogin = isValidDomainLogin; exports.stripRichTextWhitespace = stripRichTextWhitespace; exports.isValidVarName = isValidVarName; exports.isValidHeaderName = isValidHeaderName; exports.GetTokenInfo = GetTokenInfo; exports.stringEqualsOrEmpty = stringEqualsOrEmpty; exports.stringContains = stringContains; exports.cleanupString = cleanupString; exports.normalizeHtmlSpace = normalizeHtmlSpace; exports.replaceAll = replaceAll; exports.capitalizeFirstLetter = capitalizeFirstLetter; exports.escapeXml = escapeXml; exports.replaceRegex = replaceRegex; exports.maskString = maskString; exports.splitString = splitString; const collections_base_1 = require("./collections.base"); const typecheckers_1 = require("./typecheckers"); function endsWith(str, value, ignoreCase) { let str1 = str; let find = value; if (ignoreCase) { str1 = str1.toLowerCase(); find = find.toLowerCase(); } return str1.substr(str1.length - find.length) === find; } function startsWith(str, value, ignoreCase) { let str1 = str; let find = value; if (ignoreCase) { str1 = str1.toLowerCase(); find = find.toLowerCase(); } return str1.substr(0, find.length) === find; } /** remove space at start or end */ function trim(str) { return str.replace(/^\s+|\s+$/g, ''); } function trimEnd(str) { return str.replace(/\s+$/, ""); } function trimStart(str) { return str.replace(/^\s+/, ""); } function splice(str, start, delCount, insert) { return str.slice(0, start) + insert + str.slice(start + Math.abs(delCount)); } function padRight(value, length, fillString = "0") { if ((0, typecheckers_1.isNumber)(value)) value = value.toString(10); let pad = (0, typecheckers_1.isNullOrEmptyString)(fillString) ? "0" : fillString[0]; return value + Array(length - value.length + 1).join(pad); } function padLeft(value, length, fillString = "0") { if ((0, typecheckers_1.isNumber)(value)) value = value.toString(10); let pad = (0, typecheckers_1.isNullOrEmptyString)(fillString) ? "0" : fillString[0]; return Array(length - String(value).length + 1).join(pad) + value; } /** returns array of [token] found inside the string * supports token formats [Author??Created by {0}::Unknown author] will return "Author" as the token * */ function GetTokens(StringFormat) { let tokensResult = []; if ((0, typecheckers_1.isNullOrEmptyString)(StringFormat)) return tokensResult; let tokens = StringFormat.match(/\[[^\]]*\]/g); if (tokens && tokens.length > 0) { tokens.forEach(token => { let key = token.slice(1, token.length - 1); key = GetTokenInfo(key).tokenName; if (tokensResult.indexOf(key) < 0) tokensResult.push(key); }); } return tokensResult; } /** replaces a string with [token] and [otherToken] with their matched provided values * supports token formats [Author??Created by {0}::Unknown author] */ function ReplaceTokens(StringFormat, TokenValues, options) { let skipMissingTokens = options && options.keepMissingTokens; if ((0, typecheckers_1.isNullOrUndefined)(StringFormat)) return null; if (StringFormat !== '') { let tokens = StringFormat.match(/\[[^\]]*\]/g); if (tokens && tokens.length > 0) { if ((0, typecheckers_1.isNullOrUndefined)(TokenValues)) TokenValues = {}; tokens.forEach(token => { let key = token.slice(1, token.length - 1); let tokenInfo = GetTokenInfo(key); let value = TokenValues[tokenInfo.tokenName]; let skip = false; if ((0, typecheckers_1.isNullOrUndefined)(value)) { value = ""; skip = skipMissingTokens; //if true we won't replace this one } if (!skip || tokenInfo.hasFormat) StringFormat = StringFormat.replace(token, tokenInfo.getValue(value)); }); } } return StringFormat; } /** calls replace tokens on every dictionary value, or set null keys to "". This function ignores null/empty dictionaries */ function ReplaceTokensInDictionary(Dictionary, TokenValues) { if (!(0, typecheckers_1.isNullOrUndefined)(Dictionary)) { Object.keys(Dictionary).forEach(key => { Dictionary[key] = (0, typecheckers_1.isNullOrEmptyString)(Dictionary[key]) ? "" : ReplaceTokens(Dictionary[key], TokenValues); }); } } /** Normalizes a guid string, lower case and removes {} */ function normalizeGuid(text, removeDashes) { if ((0, typecheckers_1.isNullOrEmptyString)(text) || !(0, typecheckers_1.isString)(text)) { return text; } var guid = text.toLowerCase().trim(); if (guid.startsWith("{")) { guid = guid.substr(1); } if (guid.endsWith("}")) { guid = guid.substr(0, guid.length - 1); } if (removeDashes) { guid = guid.replace(/-/g, ''); } return guid; } function isEmptyGuid(guid) { if ((0, typecheckers_1.isNullOrEmptyString)(guid)) return true; else if (Number(normalizeGuid(guid.toString(), true)) === 0) return true; return false; } function escapeRegExp(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } function isValidDomainLogin(login) { return /^[A-Za-z0-9\\._-]{7,}$/.test(login); } function stripRichTextWhitespace(value) { // richText fields in have random markup even when field is empty // \u200B zero width space // \u200C zero width non-joiner Unicode code point // \u200D zero width joiner Unicode code point // \uFEFF zero width no-break space Unicode code point return (0, typecheckers_1.isString)(value) ? value.replace(/[\u200B-\u200D\uFEFF]/g, "") : value; } /** allows min length 1, letters, numbers underscore only */ function isValidVarName(text) { return /^[A-Za-z0-9_]{1,}$/.test(text); } /** allows min length 1, letters, numbers underscore and hyphen only */ function isValidHeaderName(text) { return /^[A-Za-z0-9_-]{1,}$/.test(text); } /** returns token info with format */ function GetTokenInfo(text) { let split = text.split('??'); let hasFormat = split.length > 0 && !(0, typecheckers_1.isNullOrEmptyString)(split[1]); let formatSplit = hasFormat ? split[1].split('::') : []; let valueIfEmpty = formatSplit.length > 1 ? formatSplit[1] : ""; let formatIfNotEmpty = formatSplit[0]; let info = { tokenName: hasFormat ? split[0] : text, hasFormat: hasFormat, getValue: (value) => { if (!hasFormat) return value; else { if ((0, typecheckers_1.isNullOrEmptyString)(value)) return valueIfEmpty; else return formatIfNotEmpty.replace('{0}', value); } } }; return info; } /** return true if both strings are the same, or both are empty/null/undefined */ function stringEqualsOrEmpty(str1, str2, ignoreCase) { if ((0, typecheckers_1.isNullOrEmptyString)(str1) && (0, typecheckers_1.isNullOrEmptyString)(str2)) return true; if (ignoreCase) { if (!(0, typecheckers_1.isNullOrEmptyString)(str1)) str1 = str1.toLowerCase(); if (!(0, typecheckers_1.isNullOrEmptyString)(str2)) str2 = str2.toLowerCase(); } return str1 === str2; } /** return true if str1 contains str2 */ function stringContains(str1, str2, ignoreCase) { if ((0, typecheckers_1.isNullOrEmptyString)(str1) && (0, typecheckers_1.isNullOrEmptyString)(str2)) return true; if ((0, typecheckers_1.isNullOrEmptyString)(str1)) str1 = ""; if ((0, typecheckers_1.isNullOrEmptyString)(str2)) str2 = ""; if (ignoreCase) { str1 = str1.toLowerCase(); str2 = str2.toLowerCase(); } return str1.indexOf(str2) >= 0; } function cleanupString(str, options) { if ((0, typecheckers_1.isString)(options.replaceNewLines)) str = str.replace(/\r/g, '') //no returns .replace(/\n/g, options.replaceNewLines); //no line breaks if ((0, typecheckers_1.isString)(options.collapseMultipleDashes)) str = str.replace(/-+/g, options.collapseMultipleSpaces); //no extra spaces if ((0, typecheckers_1.isString)(options.collapseMultipleUnderscore)) str = str.replace(/_+/g, options.collapseMultipleUnderscore); //no extra spaces // do this last, so it will collapse spaces added by previous options if ((0, typecheckers_1.isString)(options.collapseMultipleSpaces)) { str = str.replace(new RegExp(String.fromCharCode(160), "g"), '') //get rid of non-breaking spaces .replace(/ +/g, options.collapseMultipleSpaces); //no extra spaces } return str; } /** normalizes &#160; to &nbsp; see Issue 752 */ function normalizeHtmlSpace(html) { if ((0, typecheckers_1.isNullOrEmptyString)(html)) return html; return html.replace(/&#160;/i, "&nbsp;"); } function replaceAll(str, find, replace, ignoreCase = false) { //must call escapeRegExp on find, to make sure it works when there are protected regex characters return str.replace(new RegExp(escapeRegExp(find), `g${ignoreCase ? 'i' : ''}`), replace); } function capitalizeFirstLetter(str) { return (0, typecheckers_1.isNullOrEmptyString)(str) ? "" : `${str.charAt(0).toUpperCase()}${str.substring(1)}`; } function escapeXml(unsafe, isAttribute = false) { if ((0, typecheckers_1.isNullOrEmptyString)(unsafe)) return ""; return isAttribute ? unsafe.replace(/[<>&'"]/g, (c) => { switch (c) { case '<': return '&lt;'; case '>': return '&gt;'; case '&': return '&amp;'; case '\'': return '&apos;'; case '"': return '&quot;'; } return c; }) : unsafe.replace(/[<>&]/g, (c) => { switch (c) { case '<': return '&lt;'; case '>': return '&gt;'; case '&': return '&amp;'; } return c; }); } /** uses regex str.match to replace each match by calling the replacer function (imported from CMS) */ function replaceRegex(str, regex, replacer) { let matches = str.match(regex); if (!matches || matches.length < 1) return str; //replace each found token only once let unique = (0, collections_base_1.makeUniqueArray)(matches); //todo: this has a bug where tokens matched contain each other, example, match numbers and prefix with #: 10, 100 will match both and produce #10 ##100 unique.forEach(m => { let replacement = replacer(m); if (!(0, typecheckers_1.isNullOrUndefined)(replacement)) //ignore nulls str = replaceAll(str, m, replacement); }); return str; } /** masks a long string, keeping X number for characters at the start/end and replacing the middle with the mask string (default: CC*****CCC) */ function maskString(str, options) { const mask = options && options.mask || "*****"; const start = options && (0, typecheckers_1.isNumber)(options.start) ? options.start : 2; const end = options && (0, typecheckers_1.isNumber)(options.end) ? options.end : 2; const prefix = start >= 0 ? str.slice(0, start) : str; const sliceEnd = str.length - end; const suffix = sliceEnd >= 0 ? str.slice(sliceEnd) : str; return `${prefix}${mask}${suffix}`; } function splitString(str, options) { let strArr = [str]; if (!(0, typecheckers_1.isNullOrUndefined)(options.marker)) strArr = str.split(options.marker); if ((0, typecheckers_1.isNumber)(options.maxLength) && options.maxLength > 0) { let splitted = []; strArr.forEach(currentStr => { while (currentStr.length > 0) { splitted.push(currentStr.slice(0, options.maxLength)); currentStr = currentStr.slice(options.maxLength); } }); strArr = splitted; } if (options.clearEmptyEntries) strArr = (0, collections_base_1.filterEmptyEntries)(strArr); return strArr; } //# sourceMappingURL=strings.js.map