first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
export async function asyncIterableToArray<T>(
iterator: AsyncIterable<T>
): Promise<T[]> {
const items: T[] = [];
for await (const item of iterator) {
items.push(item);
}
return items;
}

View File

@@ -0,0 +1,13 @@
export function chunkArray<T>(array: T[], chunkSize: number): T[][] {
return array.reduce<any>((resultArray, item, index) => {
const chunkIndex = Math.floor(index / chunkSize);
if (!resultArray[chunkIndex]) {
resultArray[chunkIndex] = [];
}
resultArray[chunkIndex].push(item);
return resultArray;
}, []);
}

View File

@@ -0,0 +1,26 @@
interface Options<T> {
map?: (item: T) => T;
}
export function groupArrayBy<T>(
arr: T[],
cb: (item: any) => string,
options?: Options<T>,
): {[key: string]: T[]} {
const result: {[key: string]: T[]} = {};
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
const bucketCategory = cb(item);
const bucket = result[bucketCategory];
item = options?.map ? options.map(arr[i]) : arr[i];
if (!Array.isArray(bucket)) {
result[bucketCategory] = [item];
} else {
result[bucketCategory].push(item);
}
}
return result;
}

View File

@@ -0,0 +1,25 @@
import {clamp} from '../number/clamp';
export function moveItemInArray<T = any>(
array: T[],
fromIndex: number,
toIndex: number
): T[] {
const from = clamp(fromIndex, 0, array.length - 1);
const to = clamp(toIndex, 0, array.length - 1);
if (from === to) {
return array;
}
const target = array[from];
const delta = to < from ? -1 : 1;
for (let i = from; i !== to; i += delta) {
array[i] = array[i + delta];
}
array[to] = target;
return array;
}

View File

@@ -0,0 +1,14 @@
export function moveItemInNewArray<T>(
array: T[],
from: number,
to: number
): T[] {
const newArray = array.slice();
newArray.splice(
to < 0 ? newArray.length + to : to,
0,
newArray.splice(from, 1)[0]
);
return newArray;
}

View File

@@ -0,0 +1,35 @@
export function moveMultipleItemsInArray<T>(
array: T[],
indexOrIndexes: number | number[],
newIndex: number
) {
const indexes = Array.isArray(indexOrIndexes)
? indexOrIndexes
: [indexOrIndexes];
const insertBefore = array[newIndex + (newIndex < indexes[0] ? 0 : 1)];
const itemsToBeMoved = indexes.map(i => array[i]);
// in original sequence order, check for presence in the removal
// list, *and* remove them from the original array
const moved = [];
for (let i = 0; i < array.length; ) {
const value = array[i];
if (itemsToBeMoved.indexOf(value) >= 0) {
moved.push(value);
array.splice(i, 1);
} else {
++i;
}
}
// find the new index of the insertion point
let insertionIndex = array.indexOf(insertBefore);
if (insertionIndex < 0) {
insertionIndex = array.length;
}
// and add the elements back in
array.splice(insertionIndex, 0, ...moved);
return array;
}

View File

@@ -0,0 +1,5 @@
export function prependToArrayAtIndex<T>(array: T[], toAdd: T[], index = 0): T[] {
const copyOfArray = [...array];
const tail = copyOfArray.splice(index + 1);
return [...copyOfArray, ...toAdd, ...tail];
}

View File

@@ -0,0 +1,22 @@
export function shuffleArray(items: any[], keepFirst = false) {
let first = keepFirst ? items.shift() : null;
let currentIndex = items.length,
temporaryValue,
randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = items[currentIndex];
items[currentIndex] = items[randomIndex];
items[randomIndex] = temporaryValue;
}
if (first) {
items.unshift(first);
}
return [...items];
}

View File

@@ -0,0 +1,77 @@
import dot from 'dot-object';
const MAX_SAFE_INTEGER = 9007199254740991;
export function sortArrayOfObjects<T extends object>(
data: T[],
orderBy: string,
orderDir: 'asc' | 'desc' = 'desc'
): T[] {
return data.sort((a, b) => {
let valueA = sortingDataAccessor(a, orderBy);
let valueB = sortingDataAccessor(b, orderBy);
// If there are data in the column that can be converted to a number,
// it must be ensured that the rest of the data
// is of the same type so as not to order incorrectly.
const valueAType = typeof valueA;
const valueBType = typeof valueB;
if (valueAType !== valueBType) {
if (valueAType === 'number') {
valueA += '';
}
if (valueBType === 'number') {
valueB += '';
}
}
// If both valueA and valueB exist (truthy), then compare the two. Otherwise, check if
// one value exists while the other doesn't. In this case, existing value should come last.
// This avoids inconsistent results when comparing values to undefined/null.
// If neither value exists, return 0 (equal).
let comparatorResult = 0;
if (valueA != null && valueB != null) {
// Check if one value is greater than the other; if equal, comparatorResult should remain 0.
if (valueA > valueB) {
comparatorResult = 1;
} else if (valueA < valueB) {
comparatorResult = -1;
}
} else if (valueA != null) {
comparatorResult = 1;
} else if (valueB != null) {
comparatorResult = -1;
}
return comparatorResult * (orderDir === 'asc' ? 1 : -1);
});
}
/**
* Data accessor function that is used for accessing data properties for sorting through
* the default sortData function.
* This default function assumes that the sort header IDs (which defaults to the column name)
* matches the data's properties (e.g. column Xyz represents data['Xyz']).
* May be set to a custom function for different behavior.
*/
function sortingDataAccessor(data: object, key: string): string {
const value = dot.pick(key, data);
if (isNumberValue(value)) {
const numberValue = Number(value);
// Numbers beyond `MAX_SAFE_INTEGER` can't be compared reliably, so we
// leave them as strings. For more info: https://goo.gl/y5vbSg
return numberValue < MAX_SAFE_INTEGER ? numberValue : value;
}
return value;
}
function isNumberValue(value: any): boolean {
// parseFloat(value) handles most of the cases we're interested in (it treats null, empty string,
// and other non-number values as NaN, where Number just uses 0) but it considers the string
// '123hello' to be a valid number. Therefore, we also check if Number(value) is NaN.
return !isNaN(parseFloat(value as any)) && !isNaN(Number(value));
}