moderndash 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.ctiignore +3 -0
  2. package/package.json +41 -0
  3. package/src/array/chunk.ts +31 -0
  4. package/src/array/difference.ts +21 -0
  5. package/src/array/differenceBy.ts +30 -0
  6. package/src/array/differenceWith.ts +31 -0
  7. package/src/array/dropRightWhile.ts +28 -0
  8. package/src/array/dropWhile.ts +24 -0
  9. package/src/array/index.ts +24 -0
  10. package/src/array/intersection.ts +20 -0
  11. package/src/array/intersectionBy.ts +26 -0
  12. package/src/array/intersectionWith.ts +33 -0
  13. package/src/array/sample.ts +18 -0
  14. package/src/array/sampleSize.ts +31 -0
  15. package/src/array/shuffle.ts +33 -0
  16. package/src/array/takeRightWhile.ts +33 -0
  17. package/src/array/takeWhile.ts +33 -0
  18. package/src/array/union.ts +16 -0
  19. package/src/array/unionBy.ts +26 -0
  20. package/src/array/unionWith.ts +31 -0
  21. package/src/array/uniq.ts +18 -0
  22. package/src/array/uniqBy.ts +25 -0
  23. package/src/array/uniqWith.ts +20 -0
  24. package/src/array/unzip.ts +20 -0
  25. package/src/array/unzipWith.ts +26 -0
  26. package/src/array/zip.ts +17 -0
  27. package/src/array/zipWith.ts +28 -0
  28. package/src/collection/countBy.ts +38 -0
  29. package/src/collection/groupBy.ts +33 -0
  30. package/src/collection/index.ts +3 -0
  31. package/src/collection/sortBy.ts +15 -0
  32. package/src/function/after.ts +23 -0
  33. package/src/function/before.ts +27 -0
  34. package/src/function/debounce.ts +124 -0
  35. package/src/function/index.ts +6 -0
  36. package/src/function/memoize.ts +59 -0
  37. package/src/function/once.ts +19 -0
  38. package/src/function/throttle.ts +11 -0
  39. package/src/helpers/collections.ts +5 -0
  40. package/src/helpers/shortHands.ts +17 -0
  41. package/src/helpers/stringModifiers.ts +18 -0
  42. package/src/helpers/typeofChecks.ts +3 -0
  43. package/src/index.ts +7 -0
  44. package/src/lang/index.ts +4 -0
  45. package/src/lang/isEmpty.ts +23 -0
  46. package/src/lang/isEqual.ts +54 -0
  47. package/src/lang/isEqualWith.ts +5 -0
  48. package/src/lang/isPlainObject.ts +3 -0
  49. package/src/object/index.ts +1 -0
  50. package/src/object/pick.ts +22 -0
  51. package/src/string/camelCase.ts +15 -0
  52. package/src/string/capitalize.ts +3 -0
  53. package/src/string/deburr.ts +5 -0
  54. package/src/string/escape.ts +10 -0
  55. package/src/string/escapeRegExp.ts +3 -0
  56. package/src/string/index.ts +11 -0
  57. package/src/string/kebabCase.ts +10 -0
  58. package/src/string/pascalCase.ts +10 -0
  59. package/src/string/snakeCase.ts +13 -0
  60. package/src/string/startCase.ts +10 -0
  61. package/src/string/stripSpecialChars.ts +6 -0
  62. package/src/string/unescape.ts +10 -0
  63. package/src/types.ts +9 -0
  64. package/test/.eslintrc.cjs +5 -0
  65. package/test/array/chunk.test.ts +19 -0
  66. package/test/array/differenceMethods.test.ts +49 -0
  67. package/test/array/dropMethods.test.ts +30 -0
  68. package/test/array/intersectionMethods.test.ts +36 -0
  69. package/test/array/shuffle.test.ts +17 -0
  70. package/test/array/takeMethods.test.ts +41 -0
  71. package/test/array/unionMethods.test.ts +41 -0
  72. package/test/array/uniqMethods.test.ts +18 -0
  73. package/test/array/unzipMethods.test.ts +13 -0
  74. package/test/array/zipMethods.test.ts +48 -0
  75. package/test/collection/countBy.test.ts +13 -0
  76. package/test/collection/groupBy.test.ts +35 -0
  77. package/test/collection/sample.test.ts +17 -0
  78. package/test/collection/sampleSize.test.ts +33 -0
  79. package/test/collection/sortBy.test.ts +31 -0
  80. package/test/function/after.test.ts +19 -0
  81. package/test/function/before.test.ts +19 -0
  82. package/test/function/debounce.test.ts +47 -0
  83. package/test/function/memoize.test.ts +33 -0
  84. package/test/function/once.test.ts +29 -0
  85. package/test/function/throttle.test.ts +24 -0
  86. package/test/lang/isEqualMethods.test.ts +98 -0
  87. package/test/string/camelCase.test.ts +13 -0
  88. package/test/string/capitalize.test.ts +17 -0
  89. package/test/string/deburr.test.ts +16 -0
  90. package/test/string/escape.test.ts +17 -0
  91. package/test/string/escapeRegExp.test.ts +18 -0
  92. package/test/string/kebabCase.test.ts +18 -0
  93. package/test/string/pascalCase.test.ts +16 -0
  94. package/test/string/snakeCase.test.ts +23 -0
  95. package/test/string/startCase.test.ts +14 -0
  96. package/test/string/stripSpecialChars.test.ts +15 -0
  97. package/test/string/unescape.test.ts +17 -0
  98. package/tsconfig.json +112 -0
  99. package/tsup.config.js +10 -0
  100. package/vitest.config.ts +27 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * This method is like `unzip` except that it accepts `iteratee` to specify
3
+ * how regrouped values should be combined. The iteratee is invoked with the
4
+ * elements of each group: (...group).
5
+ *
6
+ * @category Array
7
+ * @param iteratee - The function to combine regrouped values.
8
+ * @param array - The array of grouped elements to process.
9
+ * @returns Returns the new array of regrouped elements.
10
+ * @example
11
+ * const zipped = zip([1, 2], [10, 20], [100, 200])
12
+ * // => [[1, 10, 100], [2, 20, 200]]
13
+ *
14
+ * unzipWith(add, zipped)
15
+ * // => [3, 30, 300]
16
+ */
17
+
18
+ export function unzipWith<TInput extends unknown[], TOutput>(iteratee: (...t: TInput) => TOutput, array: TInput[]): TOutput[] {
19
+ const result: TOutput[] = [];
20
+
21
+ for (const elements of array) {
22
+ result.push(iteratee(...elements));
23
+ }
24
+
25
+ return result;
26
+ }
@@ -0,0 +1,17 @@
1
+ import { zipWith } from '@array/zipWith';
2
+
3
+ /**
4
+ * Creates an array of grouped elements, the first of which contains the first elements of the given arrays,
5
+ * the second of which contains the second elements of the given arrays, and so on.
6
+ *
7
+ * @category Array
8
+ * @param arrays - The arrays to process.
9
+ * @returns Returns the new array of grouped elements.
10
+ * @example
11
+ * zip(['a', 'b'], [1, 2], [true, false])
12
+ * // => [['a', 1, true], ['b', 2, false]]
13
+ */
14
+
15
+ export function zip<TInput>(...arrays: TInput[][]): TInput[][] {
16
+ return zipWith((...t) => t, ...arrays);
17
+ }
@@ -0,0 +1,28 @@
1
+ // Types from https://gist.github.com/briancavalier/c4af1538ae9b2e4ab97caf14306625ab
2
+ type UnZip<A extends readonly unknown[]> = {
3
+ [K in keyof A]: readonly A[K][]
4
+ };
5
+
6
+ /**
7
+ * This method is like `zip` except that it accepts `iteratee` to specify
8
+ * how grouped values should be combined. The iteratee is invoked with the
9
+ * elements of each group: (...group).
10
+ *
11
+ * @category Array
12
+ * @param combineFunc - The function to combine grouped values.
13
+ * @param arrays - The arrays to process.
14
+ * @returns Returns the new array of grouped elements.
15
+ * @example
16
+ * zipWith([1, 2], [10, 20], [100, 200], (a, b, c) => a + b + c)
17
+ * // => [111, 222]
18
+ */
19
+
20
+ export function zipWith<Args extends unknown[], TOutput>(combineFunc: (...args: Args) => TOutput, ...arrays: UnZip<Args>): TOutput[] {
21
+ const len = Math.min(...arrays.map(a => a.length));
22
+ const zipped: TOutput[] = [];
23
+ for (let i = 0; i < len; i++) {
24
+ // Typescript needs the Args hint, or it infers any[]
25
+ zipped[i] = combineFunc(...arrays.map(a => a[i]) as Args);
26
+ }
27
+ return zipped;
28
+ }
@@ -0,0 +1,38 @@
1
+ import type { Collection, RecordKey } from '../types';
2
+
3
+ import { getValuesFromCollection } from '@helpers/collections';
4
+
5
+ /**
6
+ * Creates an object composed of keys generated from the results of running
7
+ * each element of `collection` thru `iteratee`. The corresponding value of
8
+ * each key is the number of times the key was returned by `iteratee`.
9
+ *
10
+ * @category Collection
11
+ * @param iteratee - The iteratee to transform keys.
12
+ * @param collection - The array or object to iterate over.
13
+ * @returns Returns the composed aggregate object.
14
+ * @example
15
+ * const users = [
16
+ * { 'user': 'barney', 'active': true },
17
+ * { 'user': 'betty', 'active': true },
18
+ * { 'user': 'fred', 'active': false }
19
+ * ]
20
+ *
21
+ * countBy(value => value.active, users);
22
+ * // => { 'true': 2, 'false': 1 }
23
+ */
24
+
25
+ export function countBy<TInput, TKey extends RecordKey>(iteratee: (value: TInput) => TKey, collection: Collection<TInput>): Record<TKey, number> {
26
+ const result = {} as Record<TKey, number>;
27
+ const values = getValuesFromCollection(collection);
28
+ for (const value of values) {
29
+ const key = iteratee(value);
30
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
31
+ if (result[key] === undefined) {
32
+ result[key] = 1;
33
+ } else {
34
+ result[key] += 1;
35
+ }
36
+ }
37
+ return result;
38
+ }
@@ -0,0 +1,33 @@
1
+ import type { RecordKey, Collection } from '../types';
2
+
3
+ import { getValuesFromCollection } from '@helpers/collections';
4
+
5
+
6
+ /**
7
+ * Creates an object composed of keys generated from the results of running
8
+ * each element of `collection` thru `iteratee`. The order of grouped values
9
+ * is determined by the order they occur in `collection`. The corresponding
10
+ * value of each key is an array of elements responsible for generating the
11
+ * key.
12
+ *
13
+ * @category Collection
14
+ * @param collection The array or object to iterate over.
15
+ * @param iteratee The iteratee to transform keys.
16
+ * @returns Returns the composed aggregate object.
17
+ * @example
18
+ *
19
+ * groupBy(Math.floor, [6.1, 4.2, 6.3])
20
+ * // => { '4': [4.2], '6': [6.1, 6.3] }
21
+ */
22
+
23
+ export function groupBy<T, U extends RecordKey>(iteratee: (value: T) => U, collection: Collection<T>): Record<U, T[]> {
24
+ const result = {} as Record<U, T[]>;
25
+ const values = getValuesFromCollection(collection);
26
+ for (const value of values) {
27
+ const key = iteratee(value);
28
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
29
+ result[key] = result[key] ?? [];
30
+ result[key].push(value);
31
+ }
32
+ return result;
33
+ }
@@ -0,0 +1,3 @@
1
+ export * from './countBy';
2
+ export * from './groupBy';
3
+ export * from './sortBy';
@@ -0,0 +1,15 @@
1
+ import type { NoUnion } from '../types';
2
+
3
+ export function sortBy<T, U>(iteratee: (item: T) => NoUnion<number | bigint | Date | string, U>, array: T[]): T[] {
4
+ return array.sort((a, b) => {
5
+ const aValue = iteratee(a);
6
+ const bValue = iteratee(b);
7
+ if (aValue < bValue) {
8
+ return -1;
9
+ }
10
+ if (aValue > bValue) {
11
+ return 1;
12
+ }
13
+ return 0;
14
+ });
15
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The opposite of `before`. This method creates a function that invokes `func` once it's called `n` or more times.
3
+ *
4
+ * @category Function
5
+ * @param n The number of calls before `func` is invoked.
6
+ * @param func The function to restrict.
7
+ * @returns Returns the new restricted function.
8
+ * @example
9
+ * const caution = () => alert("Caution!");
10
+ *
11
+ * // Display alert only after it has been called 5 times
12
+ * after(5, caution)
13
+ */
14
+
15
+ export function after<TFunc extends (...args: Parameters<TFunc>) => ReturnType<TFunc>>(n: number, func: TFunc) {
16
+ let count = 1;
17
+ return (...args: Parameters<TFunc>): ReturnType<TFunc> | undefined => {
18
+ if (count >= n) {
19
+ return func(...args);
20
+ }
21
+ count += 1;
22
+ };
23
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Creates a function that invokes `func`, with the `this` binding and arguments
3
+ * of the created function, while it's called less than `n` times. Subsequent
4
+ * calls to the created function return the result of the last `func` invocation.
5
+ *
6
+ * @category Function
7
+ * @param n - The number of calls at which `func` is no longer invoked.
8
+ * @param func - The function to restrict.
9
+ * @returns Returns the new restricted function.
10
+ * @example
11
+ * const caution = () => alert("Caution!");
12
+ *
13
+ * // Only call caution two times
14
+ * before(2, caution)
15
+ */
16
+
17
+ export function before<TFunc extends (...args: Parameters<TFunc>) => ReturnType<TFunc>>(n: number, func: TFunc): TFunc {
18
+ let count = 0;
19
+ let result: ReturnType<TFunc>;
20
+ return ((...args: Parameters<TFunc>): ReturnType<TFunc> => {
21
+ if (count < n) {
22
+ count += 1;
23
+ result = func(...args);
24
+ }
25
+ return result;
26
+ }) as TFunc;
27
+ }
@@ -0,0 +1,124 @@
1
+
2
+ // TODO this is a port from lodash, it probably can be improved and shortened, also fix TS errors
3
+ export function debounce<T extends (...args: Parameters<T>) => ReturnType<T>>(
4
+ fn: T, wait = 0, options: { leading?: boolean, maxWait?: number, trailing?: boolean } = {}
5
+ ): (this: ThisParameterType<T>, ...args: Parameters<T>) => ReturnType<T> {
6
+ let lastArgs: Parameters<T> | undefined;
7
+ let lastThis: ThisParameterType<T> | undefined;
8
+ let result: ReturnType<T>;
9
+ let timerId: ReturnType<typeof setTimeout> | undefined;
10
+ let lastCallTime: number | undefined;
11
+ let lastInvokeTime = 0;
12
+ const maxing = options.maxWait ?? false;
13
+ const leading = options.leading ?? false;
14
+ const trailing = options.trailing ?? true;
15
+ const maxWait = options.maxWait ?? 0;
16
+
17
+ function invokeFunc(time: number) {
18
+ const args: Parameters<T> | undefined = lastArgs;
19
+ const thisArg: ThisParameterType<T> | undefined = lastThis;
20
+
21
+ lastArgs = lastThis = undefined;
22
+ lastInvokeTime = time;
23
+ // @ts-ignore
24
+ result = fn.apply(thisArg, args);
25
+ return result;
26
+ }
27
+
28
+ function leadingEdge(time: number) {
29
+ // Reset any `maxWait` timer.
30
+ lastInvokeTime = time;
31
+ // Start the timer for the trailing edge.
32
+ timerId = setTimeout(timerExpired, wait);
33
+ // Invoke the leading edge.
34
+ return leading ? invokeFunc(time) : result;
35
+ }
36
+
37
+ function remainingWait(time: number) {
38
+ // @ts-ignore
39
+ const timeSinceLastCall = time - lastCallTime;
40
+ const timeSinceLastInvoke = time - lastInvokeTime;
41
+ const timeWaiting = wait - timeSinceLastCall;
42
+
43
+ return maxing
44
+ ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
45
+ : timeWaiting;
46
+ }
47
+
48
+ function shouldInvoke(time: number) {
49
+ if (lastCallTime === undefined)
50
+ return true;
51
+
52
+ const timeSinceLastCall = time - lastCallTime;
53
+ const timeSinceLastInvoke = time - lastInvokeTime;
54
+
55
+ // Either this is the first call, activity has stopped and we're at the
56
+ // trailing edge, the system time has gone backwards and we're treating
57
+ // it as the trailing edge, or we've hit the `maxWait` limit.
58
+ return timeSinceLastCall >= wait || timeSinceLastCall < 0 || (maxing && timeSinceLastInvoke >= maxWait);
59
+ }
60
+
61
+ function timerExpired() {
62
+ const time = Date.now();
63
+ if (shouldInvoke(time)) {
64
+ return trailingEdge(time);
65
+ }
66
+ // Restart the timer.
67
+ timerId = setTimeout(timerExpired, remainingWait(time));
68
+ }
69
+
70
+ function trailingEdge(time: number) {
71
+ timerId = undefined;
72
+
73
+ // Only invoke if we have `lastArgs` which means `fn` has been
74
+ // debounced at least once.
75
+ if (trailing && lastArgs) {
76
+ return invokeFunc(time);
77
+ }
78
+ lastArgs = lastThis = undefined;
79
+ return result;
80
+ }
81
+
82
+ function cancel() {
83
+ if (timerId !== undefined) {
84
+ clearTimeout(timerId);
85
+ }
86
+ lastInvokeTime = 0;
87
+ lastArgs = lastCallTime = lastThis = timerId = undefined;
88
+ }
89
+
90
+ function flush() {
91
+ return timerId === undefined ? result : trailingEdge(Date.now());
92
+ }
93
+
94
+ function debounced(this: ThisParameterType<T>, ...args: Parameters<T>): ReturnType<T> {
95
+ const time = Date.now();
96
+ const isInvoking = shouldInvoke(time);
97
+
98
+ lastArgs = args;
99
+ // TODO Fix this assignment
100
+ // eslint-disable-next-line @typescript-eslint/no-this-alias,unicorn/no-this-assignment
101
+ lastThis = this;
102
+ lastCallTime = time;
103
+
104
+ if (isInvoking) {
105
+ if (timerId === undefined) {
106
+ return leadingEdge(lastCallTime);
107
+ }
108
+ if (maxing) {
109
+ // Handle invocations in a tight loop.
110
+ clearTimeout(timerId);
111
+ timerId = setTimeout(timerExpired, wait);
112
+ return invokeFunc(lastCallTime);
113
+ }
114
+ }
115
+ if (timerId === undefined) {
116
+ timerId = setTimeout(timerExpired, wait);
117
+ }
118
+ return result;
119
+ }
120
+
121
+ debounced.cancel = cancel;
122
+ debounced.flush = flush;
123
+ return debounced;
124
+ }
@@ -0,0 +1,6 @@
1
+ export * from './after';
2
+ export * from './before';
3
+ export * from './debounce';
4
+ export * from './memoize';
5
+ export * from './once';
6
+ export * from './throttle';
@@ -0,0 +1,59 @@
1
+ const defaultResolver = (...args: unknown[]) => JSON.stringify(args);
2
+ type Cache = Map<string | symbol, unknown>;
3
+
4
+ /**
5
+ * Creates a function that memoizes the result of `func`. If `resolver` is
6
+ * provided, it determines the cache key for storing the result based on the
7
+ * arguments provided to the memoized function. By default, all arguments
8
+ * provided to the memoized function are used as the map cache key.
9
+ *
10
+ * **Note:** The cache is exposed as the `cache` property on the memoized
11
+ * function. Its creation may be customized by replacing the `memoize.Cache`
12
+ * constructor with one whose instances implement the
13
+ * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
14
+ * method interface of `clear`, `delete`, `get`, `has`, and `set`.
15
+ *
16
+ * @category Function
17
+ * @param func - The function to have its output memoized.
18
+ * @param resolver - The function to resolve the cache key.
19
+ * @returns Returns the new memoized function.
20
+ * @example
21
+ * const object = \{ 'a': 1, 'b': 2 \}
22
+ *
23
+ * const values = memoize(values)
24
+ * values(object)
25
+ * // => [1, 2]
26
+ *
27
+ * values(object)
28
+ * // => [1, 2]
29
+ *
30
+ * object.a = 2
31
+ * values(object)
32
+ * // => [2, 2]
33
+ *
34
+ * // Modify the result cache.
35
+ * values.cache.set(object, ['a', 'b'])
36
+ * values(object)
37
+ * // => ['a', 'b']
38
+ *
39
+ * // Replace `memoize.Cache`.
40
+ * memoize.Cache = WeakMap
41
+ */
42
+
43
+ export function memoize<TFunc extends (...args: Parameters<TFunc>) => ReturnType<TFunc>>(
44
+ func: TFunc, resolver: ((...args: Parameters<TFunc>) => string | symbol) = defaultResolver
45
+ ): TFunc & { cache: Cache } {
46
+ const cache: Cache = new Map();
47
+ const memoizedFunc = (...args: Parameters<TFunc>): ReturnType<TFunc> => {
48
+ const key = resolver(...args);
49
+ if (cache.has(key)) {
50
+ // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
51
+ return cache.get(key) as ReturnType<TFunc>;
52
+ }
53
+ const result = func(...args);
54
+ cache.set(key, result);
55
+ return result;
56
+ };
57
+ memoizedFunc.cache = cache;
58
+ return memoizedFunc as TFunc & { cache: Cache };
59
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
3
+ * to the function return the value of the first invocation. The `func` is
4
+ * invoked with the `this` binding and arguments of the created function.
5
+ *
6
+ * @category Function
7
+ * @param func - The function to restrict.
8
+ * @returns Returns the new restricted function.
9
+ * @example
10
+ * const initialize = once(createApplication)
11
+ * initialize()
12
+ * initialize()
13
+ * // => `createApplication` is invoked once
14
+ */
15
+ import { before } from '@function/before';
16
+
17
+ export function once<TFunc extends (...args: Parameters<TFunc>) => ReturnType<TFunc>>(func: TFunc): TFunc {
18
+ return before(1, func);
19
+ }
@@ -0,0 +1,11 @@
1
+ import { debounce } from '@function/debounce';
2
+
3
+ export function throttle<T extends (...args: Parameters<T>) => ReturnType<T>>(
4
+ func: T, wait = 0, options: { leading?: boolean, trailing?: boolean } = {}
5
+ ): (this: ThisParameterType<T>, ...args: Parameters<T>) => ReturnType<T> {
6
+ return debounce(func, wait, {
7
+ leading: options.leading ?? true,
8
+ maxWait: wait,
9
+ trailing: options.trailing ?? true
10
+ });
11
+ }
@@ -0,0 +1,5 @@
1
+ import type { Collection } from '../types';
2
+
3
+ export function getValuesFromCollection<T>(collection: Collection<T>): T[] {
4
+ return Array.isArray(collection) ? collection : Object.values(collection);
5
+ }
@@ -0,0 +1,17 @@
1
+ import type { IterateeFunction, PropertyShorthand } from '../types';
2
+
3
+ import { isObjectKey } from '@helpers/typeofChecks';
4
+
5
+ export function getPropertyShorthand<T, K extends keyof T>(key: K): (object: T) => T[K] {
6
+ return object => object[key];
7
+ }
8
+
9
+ export function getIterateFunction<T>(iteratee: IterateeFunction<T> | PropertyShorthand<T>) {
10
+ if (typeof iteratee === 'function') {
11
+ return iteratee;
12
+ } else if (isObjectKey(iteratee)) {
13
+ return getPropertyShorthand(iteratee);
14
+ } else {
15
+ throw new TypeError('Expected iteratee to be a function or a property name');
16
+ }
17
+ }
@@ -0,0 +1,18 @@
1
+ import { deburr } from '@string/deburr';
2
+
3
+ export function splitWords(str: string): string[] {
4
+ str = deburr(str);
5
+
6
+ // Split non-alphanumeric characters with spaces and deal with camel/PascalCase
7
+ const regex = new RegExp(
8
+ '[^\\dA-Za-z]' + // match any character that is not a letter or a digit
9
+ '|' + // or
10
+ '(?<=[a-z])' + // lookbehind for a lowercase letter
11
+ '(?=[A-Z])' + // lookahead for an uppercase letter
12
+ '|' + // or
13
+ '(?<=[A-Z])' + // lookbehind for an uppercase letter
14
+ '(?=[A-Z][a-z])' // lookahead for an uppercase letter followed by a lowercase letter
15
+ );
16
+
17
+ return str.split(regex).filter(Boolean);
18
+ }
@@ -0,0 +1,3 @@
1
+ export function isObjectKey(key: unknown): key is keyof object {
2
+ return typeof key === 'string' || typeof key === 'number' || typeof key === 'symbol';
3
+ }
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './array';
2
+ export * from './collection';
3
+ export * from './function';
4
+ export * from './lang';
5
+ export * from './object';
6
+ export * from './string';
7
+ export * from './types';
@@ -0,0 +1,4 @@
1
+ export * from './isEmpty';
2
+ export * from './isEqual';
3
+ export * from './isEqualWith';
4
+ export * from './isPlainObject';
@@ -0,0 +1,23 @@
1
+ export function isEmpty(value: unknown): boolean {
2
+ if (value === null || value === undefined) {
3
+ return true;
4
+ }
5
+
6
+ if (typeof value === 'string' || Array.isArray(value)) {
7
+ return value.length === 0;
8
+ }
9
+
10
+ if (typeof value === 'number') {
11
+ return false;
12
+ }
13
+
14
+ if (value instanceof Map || value instanceof Set) {
15
+ return value.size === 0;
16
+ }
17
+
18
+ if (typeof value === 'object') {
19
+ return Object.keys(value).length === 0;
20
+ }
21
+
22
+ return false;
23
+ }
@@ -0,0 +1,54 @@
1
+ import type { RecordKey } from '../types';
2
+
3
+ export function isEqual(value1: unknown, value2: unknown): boolean {
4
+ if (value1 === value2) return true;
5
+
6
+ if (Array.isArray(value1) && Array.isArray(value2)) {
7
+ return isSameArray(value1, value2);
8
+ }
9
+
10
+ if (value1 instanceof RegExp && value2 instanceof RegExp) {
11
+ return value1.toString() === value2.toString();
12
+ }
13
+
14
+ if (isObject(value1) && isObject(value2)) {
15
+ return isSameObject(value1, value2);
16
+ }
17
+
18
+ return false;
19
+ }
20
+
21
+ type KeyValueObject = Record<RecordKey, unknown>;
22
+ function isObject(value: unknown): value is KeyValueObject {
23
+ return typeof value === 'object'
24
+ && value !== null
25
+ && !Array.isArray(value)
26
+ && Object.prototype.toString.call(value) === '[object Object]';
27
+ }
28
+
29
+ function isSameObject(value1: KeyValueObject, value2: KeyValueObject) {
30
+ // check if the objects have the same keys
31
+ const keys1 = Object.keys(value1);
32
+ const keys2 = Object.keys(value2);
33
+ if (!isEqual(keys1, keys2)) return false;
34
+
35
+ // check if the values of each key in the objects are equal
36
+ for (const key of keys1) {
37
+ if (!isEqual(value1[key], value2[key])) return false;
38
+ }
39
+
40
+ // the objects are deeply equal
41
+ return true;
42
+ }
43
+
44
+ function isSameArray(value1: unknown[], value2: unknown[]) {
45
+ // check if the arrays have the same length
46
+ if (value1.length !== value2.length) return false;
47
+
48
+ // check if the values of each element in the arrays are equal
49
+ for (const [i, element] of value1.entries()) {
50
+ if (!isEqual(element, value2[i])) return false;
51
+ }
52
+
53
+ return true;
54
+ }
@@ -0,0 +1,5 @@
1
+ import { isEqual } from '@lang/isEqual';
2
+
3
+ export function isEqualWith<T>(customizer: (value: T) => unknown, a: T, b: T): boolean {
4
+ return isEqual(customizer(a), customizer(b));
5
+ }
@@ -0,0 +1,3 @@
1
+ export function isPlainObject(value: unknown): value is object {
2
+ return value !== null && typeof value === 'object' && value.constructor === Object;
3
+ }
@@ -0,0 +1 @@
1
+ export * from './pick';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Creates an object composed of the picked `object` properties.
3
+ *
4
+ * @category Object
5
+ * @param object The source object.
6
+ * @param keys The property paths to pick.
7
+ * @returns {Object} Returns the new object.
8
+ * @example
9
+ *
10
+ * const object = { 'a': 1, 'b': '2', 'c': 3 }
11
+ *
12
+ * pick(object, ['a', 'c'])
13
+ * // => { 'a': 1, 'c': 3 }
14
+ */
15
+
16
+ export function pick<T, K extends keyof T>(object: T, keys: K[]): Pick<T, K> {
17
+ const result = {} as Pick<T, K>;
18
+ for (const key of keys) {
19
+ result[key] = object[key];
20
+ }
21
+ return result;
22
+ }
@@ -0,0 +1,15 @@
1
+ import { splitWords } from '@helpers/stringModifiers';
2
+
3
+ export function camelCase(str: string): string {
4
+ const words = splitWords(str);
5
+
6
+ // Capitalize the first letter of each word
7
+ const camelCase = words.map((word, index) => {
8
+ if (index === 0) {
9
+ return word.toLowerCase();
10
+ }
11
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
12
+ });
13
+
14
+ return camelCase.join('');
15
+ }
@@ -0,0 +1,3 @@
1
+ export function capitalize(str: string): string {
2
+ return str.charAt(0).toUpperCase() + str.slice(1);
3
+ }
@@ -0,0 +1,5 @@
1
+ export function deburr(str: string): string {
2
+ // eslint-disable-next-line no-control-regex
3
+ return str.replace(/[^\u0000-\u007E]/g, (chr: string) =>
4
+ chr.normalize('NFD').replace(/[\u0300-\u036F]/g, ''));
5
+ }
@@ -0,0 +1,10 @@
1
+ export function escape(str: string): string {
2
+ const escapeChars: Record<string, string> = {
3
+ '&': '&amp;',
4
+ '<': '&lt;',
5
+ '>': '&gt;',
6
+ '\'': '&#39;',
7
+ '"': '&quot;'
8
+ };
9
+ return str.replace(/["&'<>]/g, char => escapeChars[char] || char);
10
+ }