UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

408 lines 16.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.numbersArray = exports.FindNextAvailableName = exports.ArrayFill = exports.PushNoDuplicate = exports.RemoveItemFromArr = exports.defaultPrimitiveGetValue = exports.GetPagedCollectionInfo = exports.FlattenGroupItems = exports.IsMultiLevelGroup = exports.GetUniqueArrayInfo = exports.makeUniqueArray = exports.flattenArray = exports.convertDictionary = exports.toArray = exports.toHash = exports.chunkArray = exports.sizeOf = exports.forEachAsync = exports.forEach = exports.sortNumberArray = exports.sortNumberArrayAsc = exports.filterEmptyEntries = exports.sortArray = exports.lastOrNullAsync = exports.lastIndexOfAsync = exports.firstOrNullAsync = exports.firstIndexOfAsync = exports.lastOrNull = exports.lastIndexOf = exports.firstOrNull = exports.firstIndexOf = exports.moveToEnd = exports.moveToStart = void 0; const typecheckers_1 = require("./typecheckers"); /** Finds an object in array based on a filter and moves it to the start of the array */ function moveToStart(arr, filter) { let index = firstIndexOf(arr, filter); if (index > 0) { let obj = arr[index]; arr.splice(index, 1); arr.unshift(obj); } } exports.moveToStart = moveToStart; /** Finds an object in array based on a filter and moves it to the end of the array */ function moveToEnd(arr, filter) { let index = firstIndexOf(arr, filter); if (index !== -1 && index !== arr.length - 1) { let obj = arr[index]; arr.splice(index, 1); arr.push(obj); } } exports.moveToEnd = moveToEnd; /** Get the first index of an object of an array, or -1 if the array is empty / null */ // export function firstIndexOf<T extends Element>(arr: HTMLCollectionOf<T>, filter?: (item: T, index?: number) => boolean, startFrom?: number): number; // export function firstIndexOf<T>(arr: T[], filter?: (item: T, index?: number) => boolean, startFrom?: number): number; function firstIndexOf(arr, filter, startFrom) { if (!(0, typecheckers_1.isNullOrUndefined)(arr) && arr.length > 0) { if ((0, typecheckers_1.isFunction)(filter)) { //use for loop so we can stop when it is found for (let i = startFrom > 0 ? startFrom : 0; i < arr.length; i++) if (filter(arr[i], i) === true) return i; } else return 0; } return -1; } exports.firstIndexOf = firstIndexOf; /** Get the first object of an array, or null if the array is empty / null * If you pass a filter, it will find the first element that matches the filter and return it, stopping the loop when it is found * */ function firstOrNull(arr, filter) { let index = firstIndexOf(arr, filter); return index < 0 ? null : arr[index]; } exports.firstOrNull = firstOrNull; /** Get the last index of an object of an array, or -1 if the array is empty / null */ function lastIndexOf(arr, filter) { if (!(0, typecheckers_1.isNullOrUndefined)(arr) && arr.length > 0) { if ((0, typecheckers_1.isFunction)(filter)) { //use for loop so we can stop when it is found for (let i = arr.length - 1; i >= 0; i--) if (filter(arr[i]) === true) return i; } else return arr.length - 1; } return -1; } exports.lastIndexOf = lastIndexOf; /** get the last element or null */ function lastOrNull(arr, filter) { let index = lastIndexOf(arr, filter); return index < 0 ? null : arr[index]; } exports.lastOrNull = lastOrNull; /** Get the first index of an object of an array, or -1 if the array is empty / null */ async function firstIndexOfAsync(arr, filter, startFrom) { if (!(0, typecheckers_1.isNullOrUndefined)(arr) && arr.length > 0) { if ((0, typecheckers_1.isFunction)(filter)) { //use for loop so we can stop when it is found for (let i = startFrom > 0 ? startFrom : 0; i < arr.length; i++) if ((await filter(arr[i], i)) === true) return i; } else return 0; } return -1; } exports.firstIndexOfAsync = firstIndexOfAsync; /** Get the first object of an array, or null if the array is empty / null * If you pass a filter, it will find the first element that matches the filter and return it, stopping the loop when it is found * */ async function firstOrNullAsync(arr, filter) { let index = await firstIndexOfAsync(arr, filter); return index < 0 ? null : arr[index]; } exports.firstOrNullAsync = firstOrNullAsync; /** Get the last index of an object of an array, or -1 if the array is empty / null */ async function lastIndexOfAsync(arr, filter) { if (!(0, typecheckers_1.isNullOrUndefined)(arr) && arr.length > 0) { if ((0, typecheckers_1.isFunction)(filter)) { //use for loop so we can stop when it is found for (let i = arr.length - 1; i >= 0; i--) if ((await filter(arr[i])) === true) return i; } else return arr.length - 1; } return -1; } exports.lastIndexOfAsync = lastIndexOfAsync; /** get the last element or null */ async function lastOrNullAsync(arr, filter) { let index = await lastIndexOfAsync(arr, filter); return index < 0 ? null : arr[index]; } exports.lastOrNullAsync = lastOrNullAsync; /** Sorts an array of complex objects, use defaultPrimitiveGetValue for default functionality */ function sortArray(arr, getValue) { if (!(0, typecheckers_1.isNullOrEmptyArray)(arr)) { if ((0, typecheckers_1.isTypeofFullNameFunction)("Intl.Collator")) { //todo: should probably use the SharePoint locale isntead of 'undefined' let collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); arr.sort((a, b) => { let va = getValue(a); let vb = getValue(b); return collator.compare(va, vb); }); } else { arr.sort((a, b) => { let va = getValue(a); if ((0, typecheckers_1.isString)(va)) va = va.toLowerCase(); let vb = getValue(b); if ((0, typecheckers_1.isString)(vb)) vb = vb.toLowerCase(); return va === vb ? 0 : va > vb ? 1 : -1; }); } } return arr; } exports.sortArray = sortArray; /** removes null, undefined or "" elements from the array */ function filterEmptyEntries(arr) { return arr.filter(val => !(0, typecheckers_1.isNullOrEmptyString)(val)); } exports.filterEmptyEntries = filterEmptyEntries; function sortNumberArrayAsc(a, b) { return a - b; } exports.sortNumberArrayAsc = sortNumberArrayAsc; function sortNumberArray(a, b) { return b - a; } exports.sortNumberArray = sortNumberArray; /** call a foreach on an object or an array, with an option to break when returning false */ function forEach(obj, func, args) { if (obj && func && (0, typecheckers_1.isFunction)(func)) { if (Array.isArray(obj) || obj.constructor && (0, typecheckers_1.getFromFullName)("constructor.name", obj) === "Array") { for (let i = 0; i < obj.length; i++) { let property = i; let value = obj[property]; let result = func(property.toString(10), value, args); if (result === false) { break; } } } else { let keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { let property = keys[i]; let value = obj[property]; let result = func(property, value, args); if (result === false) { break; } } } } } exports.forEach = forEach; async function forEachAsync(arr, handler, options) { if (!(0, typecheckers_1.isNullOrUndefined)(arr) && Object.keys(arr).length > 0) { let keys = Object.keys(arr); if (options && options.parallel) { let promises = []; keys.forEach((key, i) => { promises.push(handler(arr[key], i)); }); return Promise.all(promises); } else { let results = []; for (let i = 0; i < keys.length; i++) { results.push(await handler(arr[keys[i]], i)); } return results; } } else return []; } exports.forEachAsync = forEachAsync; function sizeOf(obj) { if (Array.isArray(obj)) return obj.length; return Object.keys(obj).length; } exports.sizeOf = sizeOf; function chunkArray(array, chunkSize) { let chunkedArray = []; for (var i = 0; i < array.length; i += chunkSize) { chunkedArray.push(array.slice(i, i + chunkSize)); } return chunkedArray; } exports.chunkArray = chunkArray; /** Takes an array and transforms it into a hash. this will assign 1 item per key, assumig getKey will be unique per item. */ function toHash(arr, getKey, filter, transformValue) { let hash = {}; if (!(0, typecheckers_1.isFunction)(transformValue)) transformValue = v => v; if ((0, typecheckers_1.isNotEmptyArray)(arr)) arr.forEach(i => { if (!(0, typecheckers_1.isFunction)(filter) || filter(i)) hash[getKey(i)] = transformValue(i); }); return hash; } exports.toHash = toHash; /** Returns an array from the values of the dictionary. */ function toArray(hash, filter, transform) { let arr = []; if (!(0, typecheckers_1.isFunction)(transform)) transform = (key, element) => element; if (!(0, typecheckers_1.isNullOrUndefined)(hash)) Object.keys(hash).forEach(key => { if (!(0, typecheckers_1.isFunction)(filter) || filter(hash[key])) arr.push(transform(key, hash[key])); }); return arr; } exports.toArray = toArray; /** returns a new dictionary, converting each entry in source using the transform function */ function convertDictionary(source, transform) { let result = {}; forEach(source, (key, value) => { result[key] = transform(value); }); return result; } exports.convertDictionary = convertDictionary; function flattenArray(array) { return array.reduce((acc, val) => acc.concat(val), []); } exports.flattenArray = flattenArray; /** careful, does not work for date/complex objects. Use GetUniqueArrayInfo if you suspect you might have Date/complex objects. */ function makeUniqueArray(arr) { return arr.filter((v, i, a) => a.indexOf(v) === i); } exports.makeUniqueArray = makeUniqueArray; /** return an array of unique values, and the first index they were found, use defaultPrimitiveGetValue for default functionality */ function GetUniqueArrayInfo(arr, getValue) { var uniqueValues = []; var uniqueArray = []; var foundValues = []; var hasDuplicates = false; var duplicateIndexes = []; if ((0, typecheckers_1.isNotEmptyArray)(arr)) { arr.forEach((item, index) => { let value = getValue(item); if (foundValues.includes(value)) { hasDuplicates = true; duplicateIndexes.push(index); } else { foundValues.push(value); uniqueValues.push({ item: item, value: value, firstIndex: index }); uniqueArray.push(item); } }); } return { /** true if duplicate values found */ hasDuplicates: hasDuplicates, /** all duplicate item indexes */ duplicateIndexes: duplicateIndexes, /** unique values and their info */ uniqueValues: uniqueValues, /** the unique version of this array */ uniqueArray: uniqueArray }; } exports.GetUniqueArrayInfo = GetUniqueArrayInfo; /** returns true if the element is a group of items */ function IsMultiLevelGroup(groupOrItem) { let asGroup = groupOrItem; return !(0, typecheckers_1.isNullOrUndefined)(asGroup.subGroups) && Array.isArray(asGroup.groupItems) && (0, typecheckers_1.isNumber)(asGroup.index) && (0, typecheckers_1.isNumber)(asGroup.depth); } exports.IsMultiLevelGroup = IsMultiLevelGroup; /** returns a flat array of groups>items ordered by groups */ function FlattenGroupItems(groups) { let flatItems = []; Object.keys(groups).forEach(groupName => { let group = groups[groupName]; if (!(0, typecheckers_1.isNullOrEmptyString)(groupName)) flatItems.push(group); let subGroups = Object.keys(group.subGroups); if ((0, typecheckers_1.isNotEmptyArray)(subGroups)) { flatItems.push(...FlattenGroupItems(group.subGroups)); } else flatItems.push(...group.groupItems); }); return flatItems; } exports.FlattenGroupItems = FlattenGroupItems; /** split a collection by page size and return the info */ function GetPagedCollectionInfo(collection, pageSize, currentPage) { let pagedItems = []; if (pageSize < 1) { pagedItems = [collection.slice()]; } else { let copy = collection.slice(); while ((0, typecheckers_1.isNotEmptyArray)(copy)) { pagedItems.push(copy.splice(0, pageSize)); } } currentPage = (0, typecheckers_1.isNumber)(currentPage) && currentPage >= 0 && currentPage < pagedItems.length ? currentPage : 0; return { /** nubmer of pages */ pages: pagedItems.length, /** page items, per page (Array of pages, each has an array of the page items) */ pagedItems: pagedItems, /** the current page */ currentPage: currentPage, /** the current page items */ currentPageItems: pagedItems[currentPage] || [], /** has more than 1 page */ hasPages: pagedItems.length > 1, allowPrev: currentPage > 0, allowNext: currentPage < pagedItems.length - 1 }; } exports.GetPagedCollectionInfo = GetPagedCollectionInfo; /** use with sortArray or get unique array to handle premitive types or dates, with a JSON.stringify to all other values */ function defaultPrimitiveGetValue(item) { return (0, typecheckers_1.isNullOrUndefined)(item) ? "" : (0, typecheckers_1.isDate)(item) ? item.getTime() : (0, typecheckers_1.isBoolean)(item) ? item === true ? 1 : 0 : (0, typecheckers_1.isNumber)(item) || (0, typecheckers_1.isString)(item) ? item : JSON.stringify(item); } exports.defaultPrimitiveGetValue = defaultPrimitiveGetValue; function RemoveItemFromArr(arr, item) { let idx = arr.indexOf(item); if (idx >= 0) arr.splice(idx, 1); } exports.RemoveItemFromArr = RemoveItemFromArr; function PushNoDuplicate(arr, item) { if (!arr.includes(item)) arr.push(item); } exports.PushNoDuplicate = PushNoDuplicate; /** fills an array with a value. Array.fill isn't available on SPFx. */ function ArrayFill(arr, value, onlyEmpty) { for (let i = 0; i < arr.length; i++) { if (onlyEmpty !== true || (0, typecheckers_1.isNullOrUndefined)(arr[i])) arr[i] = value; } return arr; } exports.ArrayFill = ArrayFill; /** give a name and a collection, and it will return a unique name availalbe, suffixing a _# to the name * example: file * return file, file_2, file_9 etc... whichever is availalbe first. */ function FindNextAvailableName(name, usedNames, options) { let nameForTest = name; if (options && options.caseSensitive !== true) { usedNames = usedNames.map(n => n.toLowerCase()); nameForTest = name.toLowerCase(); } let nameSuffix = options && options.suffix || ""; let suffixIdx = 0; let suffixStr = ""; while (usedNames.indexOf(`${nameForTest}${suffixStr}${nameSuffix}`) >= 0) { suffixIdx++; suffixStr = "_" + suffixIdx; } return `${name}${suffixStr}${nameSuffix}`; } exports.FindNextAvailableName = FindNextAvailableName; //** returns an array of numbers from 0,1,2... */ function numbersArray(length, startFrom = 0) { //dvp build will fail without any type if ((0, typecheckers_1.isNullOrUndefined)(length) || length < 0) length = 0; let arr = Array.from(Array(length).keys()); return startFrom > 0 ? arr.map(i => i + startFrom) : arr; } exports.numbersArray = numbersArray; //# sourceMappingURL=collections.base.js.map