refactor(editor): use lodash (#10657)

This commit is contained in:
Saul-Mirone
2025-03-06 09:00:00 +00:00
parent 8062893603
commit 7ae9daa6f6
46 changed files with 160 additions and 555 deletions
@@ -1,8 +1,6 @@
export * from './crypto.js';
export * from './disposable.js';
export * from './function.js';
export * from './is-equal.js';
export * from './iterable.js';
export * from './logger.js';
export * from './signal-watcher.js';
export * from './slot.js';
@@ -1,54 +0,0 @@
// https://stackoverflow.com/questions/31538010/test-if-a-variable-is-a-primitive-rather-than-an-object
export function isPrimitive(
a: unknown
): a is null | undefined | boolean | number | string {
return a !== Object(a);
}
export function assertType<T>(_: unknown): asserts _ is T {}
export type Equals<X, Y> =
///
(<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
? true
: false;
type Allowed =
| unknown
| void
| null
| undefined
| boolean
| number
| string
| unknown[]
| object;
export function isEqual<T extends Allowed, U extends T>(
val: T,
expected: U
): Equals<T, U> {
const a = isPrimitive(val);
const b = isPrimitive(expected);
if (a && b) {
if (!Object.is(val, expected)) {
return false as Equals<T, U>;
}
} else if (a !== b) {
return false as Equals<T, U>;
} else {
if (Array.isArray(val) && Array.isArray(expected)) {
if (val.length !== expected.length) {
return false as Equals<T, U>;
}
return val.every((x, i) => isEqual(x, expected[i])) as Equals<T, U>;
} else if (typeof val === 'object' && typeof expected === 'object') {
const obj1 = Object.entries(val as Record<string, unknown>);
const obj2 = Object.entries(expected as Record<string, unknown>);
if (obj1.length !== obj2.length) {
return false as Equals<T, U>;
}
return obj1.every((x, i) => isEqual(x, obj2[i])) as Equals<T, U>;
}
}
return true as Equals<T, U>;
}
@@ -1,218 +0,0 @@
/**
*
* @example
* ```ts
* const items = [
* {name: 'a', classroom: 'c1'},
* {name: 'b', classroom: 'c2'},
* {name: 'a', classroom: 't0'}
* ]
* const counted = countBy(items1, i => i.name);
* // counted: { a: 2, b: 1}
* ```
*/
export function countBy<T>(
items: T[],
key: (item: T) => string | number | null
): Record<string, number> {
const count: Record<string, number> = {};
items.forEach(item => {
const k = key(item);
if (k === null) return;
if (!count[k]) {
count[k] = 0;
}
count[k] += 1;
});
return count;
}
/**
* @example
* ```ts
* const items = [{n: 1}, {n: 2}]
* const max = maxBy(items, i => i.n);
* // max: {n: 2}
* ```
*/
export function maxBy<T>(items: T[], value: (item: T) => number): T | null {
if (!items.length) {
return null;
}
let maxItem = items[0];
let max = value(maxItem);
for (let i = 1; i < items.length; i++) {
const item = items[i];
const v = value(item);
if (v > max) {
max = v;
maxItem = item;
}
}
return maxItem;
}
/**
* Checks if there are at least `n` elements in the array that match the given condition.
*
* @param arr - The input array of elements.
* @param matchFn - A function that takes an element of the array and returns a boolean value
* indicating if the element matches the desired condition.
* @param n - The minimum number of matching elements required.
* @returns A boolean value indicating if there are at least `n` matching elements in the array.
*
* @example
* const arr = [1, 2, 3, 4, 5];
* const isEven = (num: number): boolean => num % 2 === 0;
* console.log(atLeastNMatches(arr, isEven, 2)); // Output: true
*/
export function atLeastNMatches<T>(
arr: T[],
matchFn: (element: T) => boolean,
n: number
): boolean {
let count = 0;
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let i = 0; i < arr.length; i++) {
if (matchFn(arr[i])) {
count++;
if (count >= n) {
return true;
}
}
}
return false;
}
/**
* Groups an array of elements based on a provided key function.
*
* @example
* interface Student {
* name: string;
* age: number;
* }
* const students: Student[] = [
* { name: 'Alice', age: 25 },
* { name: 'Bob', age: 23 },
* { name: 'Cathy', age: 25 },
* ];
* const groupedByAge = groupBy(students, (student) => student.age.toString());
* console.log(groupedByAge);
* // Output: {
* '23': [ { name: 'Bob', age: 23 } ],
* '25': [ { name: 'Alice', age: 25 }, { name: 'Cathy', age: 25 } ]
* }
*/
export function groupBy<T, K extends string>(
arr: T[],
key: K | ((item: T) => K)
): Record<K, T[]> {
const result = {} as Record<string, T[]>;
for (const item of arr) {
const groupKey = (
typeof key === 'function' ? key(item) : (item as any)[key]
) as string;
if (!result[groupKey]) {
result[groupKey] = [];
}
result[groupKey].push(item);
}
return result;
}
export function pickArray<T>(target: Array<T>, keys: number[]): Array<T> {
return keys.reduce((pre, key) => {
pre.push(target[key]);
return pre;
}, [] as T[]);
}
export function pick<T, K extends keyof T>(
target: T,
keys: K[]
): Record<K, T[K]> {
return keys.reduce(
(pre, key) => {
pre[key] = target[key];
return pre;
},
{} as Record<K, T[K]>
);
}
export function pickValues<T, K extends keyof T>(
target: T,
keys: K[]
): Array<T[K]> {
return keys.reduce(
(pre, key) => {
pre.push(target[key]);
return pre;
},
[] as Array<T[K]>
);
}
export function lastN<T>(target: Array<T>, n: number) {
return target.slice(target.length - n, target.length);
}
export function isEmpty(obj: unknown) {
if (Object.getPrototypeOf(obj) === Object.prototype) {
return Object.keys(obj as object).length === 0;
}
if (Array.isArray(obj) || typeof obj === 'string') {
return (obj as Array<unknown>).length === 0;
}
return false;
}
export function keys<T>(obj: T): (keyof T)[] {
return Object.keys(obj as object) as (keyof T)[];
}
export function values<T>(obj: T): T[keyof T][] {
return Object.values(obj as object);
}
type IterableType<T> = T extends Array<infer U> ? U : T;
export function last<T extends Iterable<unknown>>(
iterable: T
): IterableType<T> | undefined {
if (Array.isArray(iterable)) {
return iterable[iterable.length - 1];
}
let last: unknown | undefined;
for (const item of iterable) {
last = item;
}
return last as IterableType<T>;
}
export function nToLast<T extends Iterable<unknown>>(
iterable: T,
n: number
): IterableType<T> | undefined {
if (Array.isArray(iterable)) {
return iterable[iterable.length - n];
}
const arr = [...iterable];
return arr[arr.length - n] as IterableType<T>;
}
@@ -10,3 +10,5 @@ export type DeepPartial<T> = {
: DeepPartial<T[P]>
: T[P];
};
export function assertType<T>(_: unknown): asserts _ is T {}