@web-ts-toolkit/utils 0.27.0 → 0.29.0
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.
- package/README.md +14 -4
- package/index.d.mts +15 -1
- package/index.d.ts +15 -1
- package/index.js +133 -4
- package/index.mjs +125 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ pnpm add @web-ts-toolkit/utils
|
|
|
19
19
|
## Quick Start
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import { get,
|
|
22
|
+
import { get, groupBy, normalizeUrlPath, parseBooleanString, startCase, sumBy } from '@web-ts-toolkit/utils';
|
|
23
23
|
|
|
24
24
|
const payload = {
|
|
25
25
|
user: {
|
|
@@ -30,15 +30,25 @@ const payload = {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
get(payload, 'user.profile.name');
|
|
33
|
-
|
|
33
|
+
groupBy(
|
|
34
|
+
[
|
|
35
|
+
{ type: 'fruit', name: 'apple' },
|
|
36
|
+
{ type: 'fruit', name: 'banana' },
|
|
37
|
+
{ type: 'vegetable', name: 'carrot' },
|
|
38
|
+
],
|
|
39
|
+
'type',
|
|
40
|
+
);
|
|
41
|
+
startCase('api_response_time');
|
|
42
|
+
sumBy([{ hours: 2 }, { hours: 3 }], 'hours');
|
|
34
43
|
normalizeUrlPath('api//users');
|
|
35
44
|
parseBooleanString('true', false);
|
|
36
45
|
```
|
|
37
46
|
|
|
38
47
|
## Main Exports
|
|
39
48
|
|
|
40
|
-
- object helpers: `get`, `set`, `pick`, `omit`, `assign`, `cloneDeep`
|
|
41
|
-
- collection helpers: `map`, `filter`, `reduce`, `find`, `flatten`, `uniq`, `orderBy`
|
|
49
|
+
- object helpers: `get`, `set`, `pick`, `pickBy`, `omit`, `assign`, `cloneDeep`, `mapKeys`
|
|
50
|
+
- collection helpers: `map`, `filter`, `reduce`, `find`, `flatten`, `uniq`, `orderBy`, `groupBy`, `sum`, `sumBy`
|
|
51
|
+
- string helpers: `startCase`, `upperCase`
|
|
42
52
|
- guards: `isArray`, `isPlainObject`, `isString`, `isPromise`
|
|
43
53
|
- URL helpers: `addLeadingSlash`, `removeConsecutiveSlashesFromUrl`, `normalizeUrlPath`
|
|
44
54
|
|
package/index.d.mts
CHANGED
|
@@ -27,6 +27,8 @@ type PropertyPath = string | number | Array<string | number>;
|
|
|
27
27
|
|
|
28
28
|
declare function get<T = unknown>(object: unknown, path: PropertyPath, defaultValue?: T): T;
|
|
29
29
|
|
|
30
|
+
declare function groupBy<T>(collection: T[] | Record<string, T> | null | undefined, iteratee: string | number | ((value: T, key: number | string, collection: T[] | Record<string, T>) => unknown)): Record<string, T[]>;
|
|
31
|
+
|
|
30
32
|
declare function intersection<T>(...arrays: Array<T[] | null | undefined>): T[];
|
|
31
33
|
|
|
32
34
|
declare function intersectionBy<T>(...args: unknown[]): T[];
|
|
@@ -63,6 +65,8 @@ declare function keys(value: unknown): string[];
|
|
|
63
65
|
|
|
64
66
|
declare function map<T, TResult>(collection: T[] | Record<string, T> | null | undefined, iteratee: string | number | ((value: T, key: number | string, collection: T[] | Record<string, T>) => TResult)): TResult[];
|
|
65
67
|
|
|
68
|
+
declare function mapKeys<TValue>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => string): Record<string, TValue>;
|
|
69
|
+
|
|
66
70
|
declare function mapValues<TValue, TResult>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => TResult): Record<string, TResult>;
|
|
67
71
|
|
|
68
72
|
declare function mapValuesAsync<TObject extends Record<string, unknown>, TResult>(object: TObject, asyncFn: (value: TObject[keyof TObject], key: string, object: TObject) => Promise<TResult> | TResult): Promise<Record<string, TResult>>;
|
|
@@ -79,6 +83,8 @@ declare function padEnd(value: unknown, length?: number, chars?: string): string
|
|
|
79
83
|
|
|
80
84
|
declare function pick<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
81
85
|
|
|
86
|
+
declare function pickBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
87
|
+
|
|
82
88
|
declare function normalizeUrlPath(url: string): string;
|
|
83
89
|
|
|
84
90
|
declare function reduce<T, TResult>(collection: T[] | null | undefined, iteratee: (accumulator: TResult, value: T, key: number, collection: T[]) => TResult, accumulator?: TResult): TResult;
|
|
@@ -88,10 +94,18 @@ declare function removeConsecutiveSlashesFromUrl(url: string): string;
|
|
|
88
94
|
|
|
89
95
|
declare function set<T>(object: T, path: PropertyPath, value: unknown): T;
|
|
90
96
|
|
|
97
|
+
declare function startCase(value: unknown): string;
|
|
98
|
+
|
|
99
|
+
declare function sum(values: number[] | null | undefined): number;
|
|
100
|
+
|
|
101
|
+
declare function sumBy<T>(collection: T[] | null | undefined, iteratee: string | number | ((value: T, key: number, collection: T[]) => number | undefined)): number;
|
|
102
|
+
|
|
91
103
|
declare function toAsyncFn<TArgs extends unknown[], TResult>(fn?: ((this: unknown, ...args: TArgs) => TResult | PromiseLike<TResult>) | null, defaultValue?: TResult): (this: unknown, ...args: TArgs) => PromiseLike<unknown> | Promise<any>;
|
|
92
104
|
|
|
93
105
|
declare function toStringRecord(value: unknown): Record<string, string> | undefined;
|
|
94
106
|
|
|
95
107
|
declare function uniq<T>(array: T[] | null | undefined): T[];
|
|
96
108
|
|
|
97
|
-
|
|
109
|
+
declare function upperCase(value: unknown): string;
|
|
110
|
+
|
|
111
|
+
export { addLeadingSlash, arrayToRecord, assign, castArray, cloneDeep, compact, difference, filter, find, flatten, flattenDeep, forEach, get, groupBy, intersection, intersectionBy, isArray, isBoolean, isEmpty, isEqual, isFunction, isMatch, isNaNValue as isNaN, isNil, isNumber, isObject, isPlainObject, isPromise, isString, isUndefined, keys, map, mapKeys, mapValues, mapValuesAsync, noop, normalizeUrlPath, omit, orderBy, padEnd, parseBooleanString, pick, pickBy, reduce, removeConsecutiveSlashesFromUrl, set, startCase, sum, sumBy, toAsyncFn, toStringRecord, uniq, upperCase };
|
package/index.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ type PropertyPath = string | number | Array<string | number>;
|
|
|
27
27
|
|
|
28
28
|
declare function get<T = unknown>(object: unknown, path: PropertyPath, defaultValue?: T): T;
|
|
29
29
|
|
|
30
|
+
declare function groupBy<T>(collection: T[] | Record<string, T> | null | undefined, iteratee: string | number | ((value: T, key: number | string, collection: T[] | Record<string, T>) => unknown)): Record<string, T[]>;
|
|
31
|
+
|
|
30
32
|
declare function intersection<T>(...arrays: Array<T[] | null | undefined>): T[];
|
|
31
33
|
|
|
32
34
|
declare function intersectionBy<T>(...args: unknown[]): T[];
|
|
@@ -63,6 +65,8 @@ declare function keys(value: unknown): string[];
|
|
|
63
65
|
|
|
64
66
|
declare function map<T, TResult>(collection: T[] | Record<string, T> | null | undefined, iteratee: string | number | ((value: T, key: number | string, collection: T[] | Record<string, T>) => TResult)): TResult[];
|
|
65
67
|
|
|
68
|
+
declare function mapKeys<TValue>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => string): Record<string, TValue>;
|
|
69
|
+
|
|
66
70
|
declare function mapValues<TValue, TResult>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => TResult): Record<string, TResult>;
|
|
67
71
|
|
|
68
72
|
declare function mapValuesAsync<TObject extends Record<string, unknown>, TResult>(object: TObject, asyncFn: (value: TObject[keyof TObject], key: string, object: TObject) => Promise<TResult> | TResult): Promise<Record<string, TResult>>;
|
|
@@ -79,6 +83,8 @@ declare function padEnd(value: unknown, length?: number, chars?: string): string
|
|
|
79
83
|
|
|
80
84
|
declare function pick<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
81
85
|
|
|
86
|
+
declare function pickBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
87
|
+
|
|
82
88
|
declare function normalizeUrlPath(url: string): string;
|
|
83
89
|
|
|
84
90
|
declare function reduce<T, TResult>(collection: T[] | null | undefined, iteratee: (accumulator: TResult, value: T, key: number, collection: T[]) => TResult, accumulator?: TResult): TResult;
|
|
@@ -88,10 +94,18 @@ declare function removeConsecutiveSlashesFromUrl(url: string): string;
|
|
|
88
94
|
|
|
89
95
|
declare function set<T>(object: T, path: PropertyPath, value: unknown): T;
|
|
90
96
|
|
|
97
|
+
declare function startCase(value: unknown): string;
|
|
98
|
+
|
|
99
|
+
declare function sum(values: number[] | null | undefined): number;
|
|
100
|
+
|
|
101
|
+
declare function sumBy<T>(collection: T[] | null | undefined, iteratee: string | number | ((value: T, key: number, collection: T[]) => number | undefined)): number;
|
|
102
|
+
|
|
91
103
|
declare function toAsyncFn<TArgs extends unknown[], TResult>(fn?: ((this: unknown, ...args: TArgs) => TResult | PromiseLike<TResult>) | null, defaultValue?: TResult): (this: unknown, ...args: TArgs) => PromiseLike<unknown> | Promise<any>;
|
|
92
104
|
|
|
93
105
|
declare function toStringRecord(value: unknown): Record<string, string> | undefined;
|
|
94
106
|
|
|
95
107
|
declare function uniq<T>(array: T[] | null | undefined): T[];
|
|
96
108
|
|
|
97
|
-
|
|
109
|
+
declare function upperCase(value: unknown): string;
|
|
110
|
+
|
|
111
|
+
export { addLeadingSlash, arrayToRecord, assign, castArray, cloneDeep, compact, difference, filter, find, flatten, flattenDeep, forEach, get, groupBy, intersection, intersectionBy, isArray, isBoolean, isEmpty, isEqual, isFunction, isMatch, isNaNValue as isNaN, isNil, isNumber, isObject, isPlainObject, isPromise, isString, isUndefined, keys, map, mapKeys, mapValues, mapValuesAsync, noop, normalizeUrlPath, omit, orderBy, padEnd, parseBooleanString, pick, pickBy, reduce, removeConsecutiveSlashesFromUrl, set, startCase, sum, sumBy, toAsyncFn, toStringRecord, uniq, upperCase };
|
package/index.js
CHANGED
|
@@ -32,6 +32,7 @@ __export(index_exports, {
|
|
|
32
32
|
flattenDeep: () => flattenDeep,
|
|
33
33
|
forEach: () => forEach,
|
|
34
34
|
get: () => get,
|
|
35
|
+
groupBy: () => groupBy,
|
|
35
36
|
intersection: () => intersection,
|
|
36
37
|
intersectionBy: () => intersectionBy,
|
|
37
38
|
isArray: () => isArray,
|
|
@@ -50,6 +51,7 @@ __export(index_exports, {
|
|
|
50
51
|
isUndefined: () => isUndefined,
|
|
51
52
|
keys: () => keys,
|
|
52
53
|
map: () => map,
|
|
54
|
+
mapKeys: () => mapKeys,
|
|
53
55
|
mapValues: () => mapValues,
|
|
54
56
|
mapValuesAsync: () => mapValuesAsync,
|
|
55
57
|
noop: () => noop,
|
|
@@ -59,12 +61,17 @@ __export(index_exports, {
|
|
|
59
61
|
padEnd: () => padEnd,
|
|
60
62
|
parseBooleanString: () => parseBooleanString,
|
|
61
63
|
pick: () => pick,
|
|
64
|
+
pickBy: () => pickBy,
|
|
62
65
|
reduce: () => reduce,
|
|
63
66
|
removeConsecutiveSlashesFromUrl: () => removeConsecutiveSlashesFromUrl,
|
|
64
67
|
set: () => set,
|
|
68
|
+
startCase: () => startCase,
|
|
69
|
+
sum: () => sum,
|
|
70
|
+
sumBy: () => sumBy,
|
|
65
71
|
toAsyncFn: () => toAsyncFn,
|
|
66
72
|
toStringRecord: () => toStringRecord,
|
|
67
|
-
uniq: () => uniq
|
|
73
|
+
uniq: () => uniq,
|
|
74
|
+
upperCase: () => upperCase
|
|
68
75
|
});
|
|
69
76
|
module.exports = __toCommonJS(index_exports);
|
|
70
77
|
|
|
@@ -94,6 +101,7 @@ function castArray(value) {
|
|
|
94
101
|
|
|
95
102
|
// src/_internal.ts
|
|
96
103
|
var pathPattern = /[^.[\]]+|\[(?:([^"'[\]]+)|["']([^"']+)["'])\]/g;
|
|
104
|
+
var unsafePathParts = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
97
105
|
function isObject(value) {
|
|
98
106
|
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
99
107
|
}
|
|
@@ -126,6 +134,15 @@ function toPath(path) {
|
|
|
126
134
|
});
|
|
127
135
|
return result.length > 0 ? result : [input];
|
|
128
136
|
}
|
|
137
|
+
function hasUnsafePathPart(parts) {
|
|
138
|
+
for (let index = 0; index < parts.length; index++) {
|
|
139
|
+
const part = parts[index];
|
|
140
|
+
if (typeof part === "string" && unsafePathParts.has(part)) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
129
146
|
function hasPath(value, path) {
|
|
130
147
|
const parts = toPath(path);
|
|
131
148
|
if (parts.length === 0) {
|
|
@@ -160,7 +177,7 @@ function setPath(target, path, value) {
|
|
|
160
177
|
return target;
|
|
161
178
|
}
|
|
162
179
|
const parts = toPath(path);
|
|
163
|
-
if (parts.length === 0) {
|
|
180
|
+
if (parts.length === 0 || hasUnsafePathPart(parts)) {
|
|
164
181
|
return target;
|
|
165
182
|
}
|
|
166
183
|
let current = target;
|
|
@@ -181,7 +198,7 @@ function deletePath(target, path) {
|
|
|
181
198
|
return;
|
|
182
199
|
}
|
|
183
200
|
const parts = toPath(path);
|
|
184
|
-
if (parts.length === 0) {
|
|
201
|
+
if (parts.length === 0 || hasUnsafePathPart(parts)) {
|
|
185
202
|
return;
|
|
186
203
|
}
|
|
187
204
|
let current = target;
|
|
@@ -227,6 +244,14 @@ function getIteratee(iteratee) {
|
|
|
227
244
|
}
|
|
228
245
|
return (value) => getPath(value, iteratee);
|
|
229
246
|
}
|
|
247
|
+
var wordPattern = /[A-Z]{2,}(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]+|[0-9]+/g;
|
|
248
|
+
function words(value) {
|
|
249
|
+
const input = String(value ?? "");
|
|
250
|
+
if (input.length === 0) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
return input.replace(/[']/g, "").match(wordPattern) ?? [];
|
|
254
|
+
}
|
|
230
255
|
function compareAscending(left, right) {
|
|
231
256
|
if (sameValueZero(left, right)) {
|
|
232
257
|
return 0;
|
|
@@ -487,6 +512,31 @@ function get(object, path, defaultValue) {
|
|
|
487
512
|
return getPath(object, path, defaultValue);
|
|
488
513
|
}
|
|
489
514
|
|
|
515
|
+
// src/groupBy.ts
|
|
516
|
+
function groupBy(collection, iteratee) {
|
|
517
|
+
if (!collection) {
|
|
518
|
+
return {};
|
|
519
|
+
}
|
|
520
|
+
const callback = getIteratee(iteratee);
|
|
521
|
+
const result = {};
|
|
522
|
+
if (Array.isArray(collection)) {
|
|
523
|
+
for (let index = 0; index < collection.length; index++) {
|
|
524
|
+
const value = collection[index];
|
|
525
|
+
const key = String(callback(value, index, collection));
|
|
526
|
+
(result[key] ??= []).push(value);
|
|
527
|
+
}
|
|
528
|
+
return result;
|
|
529
|
+
}
|
|
530
|
+
const keys2 = Object.keys(collection);
|
|
531
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
532
|
+
const key = keys2[index];
|
|
533
|
+
const value = collection[key];
|
|
534
|
+
const group = String(callback(value, key, collection));
|
|
535
|
+
(result[group] ??= []).push(value);
|
|
536
|
+
}
|
|
537
|
+
return result;
|
|
538
|
+
}
|
|
539
|
+
|
|
490
540
|
// src/intersection.ts
|
|
491
541
|
function intersection(...arrays) {
|
|
492
542
|
const [first = [], ...rest] = arrays;
|
|
@@ -640,6 +690,20 @@ function map(collection, iteratee) {
|
|
|
640
690
|
return result;
|
|
641
691
|
}
|
|
642
692
|
|
|
693
|
+
// src/mapKeys.ts
|
|
694
|
+
function mapKeys(object, iteratee) {
|
|
695
|
+
if (!object) {
|
|
696
|
+
return {};
|
|
697
|
+
}
|
|
698
|
+
const result = {};
|
|
699
|
+
const keys2 = Object.keys(object);
|
|
700
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
701
|
+
const key = keys2[index];
|
|
702
|
+
result[String(iteratee(object[key], key, object))] = object[key];
|
|
703
|
+
}
|
|
704
|
+
return result;
|
|
705
|
+
}
|
|
706
|
+
|
|
643
707
|
// src/mapValues.ts
|
|
644
708
|
function mapValues(object, iteratee) {
|
|
645
709
|
if (!object) {
|
|
@@ -725,6 +789,23 @@ function pick(object, paths) {
|
|
|
725
789
|
return result;
|
|
726
790
|
}
|
|
727
791
|
|
|
792
|
+
// src/pickBy.ts
|
|
793
|
+
function pickBy(object, predicate) {
|
|
794
|
+
if (!object) {
|
|
795
|
+
return {};
|
|
796
|
+
}
|
|
797
|
+
const result = {};
|
|
798
|
+
const keys2 = Object.keys(object);
|
|
799
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
800
|
+
const key = keys2[index];
|
|
801
|
+
const value = object[key];
|
|
802
|
+
if (predicate(value, key, object)) {
|
|
803
|
+
result[key] = value;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
|
|
728
809
|
// src/removeConsecutiveSlashesFromUrl.ts
|
|
729
810
|
function removeConsecutiveSlashesFromUrl(url) {
|
|
730
811
|
return url.replace(/\/{2,}/g, "/");
|
|
@@ -771,6 +852,42 @@ function set(object, path, value) {
|
|
|
771
852
|
return setPath(object, path, value);
|
|
772
853
|
}
|
|
773
854
|
|
|
855
|
+
// src/startCase.ts
|
|
856
|
+
function startCase(value) {
|
|
857
|
+
return words(value).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// src/sum.ts
|
|
861
|
+
function sum(values) {
|
|
862
|
+
if (!Array.isArray(values)) {
|
|
863
|
+
return 0;
|
|
864
|
+
}
|
|
865
|
+
let result = 0;
|
|
866
|
+
for (let index = 0; index < values.length; index++) {
|
|
867
|
+
const value = values[index];
|
|
868
|
+
if (value !== void 0) {
|
|
869
|
+
result += value;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return result;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// src/sumBy.ts
|
|
876
|
+
function sumBy(collection, iteratee) {
|
|
877
|
+
if (!Array.isArray(collection)) {
|
|
878
|
+
return 0;
|
|
879
|
+
}
|
|
880
|
+
const callback = getIteratee(iteratee);
|
|
881
|
+
let result = 0;
|
|
882
|
+
for (let index = 0; index < collection.length; index++) {
|
|
883
|
+
const current = callback(collection[index], index, collection);
|
|
884
|
+
if (current !== void 0) {
|
|
885
|
+
result += current;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return result;
|
|
889
|
+
}
|
|
890
|
+
|
|
774
891
|
// src/toAsyncFn.ts
|
|
775
892
|
function toAsyncFn(fn, defaultValue) {
|
|
776
893
|
if (!fn) return () => Promise.resolve(defaultValue);
|
|
@@ -801,6 +918,11 @@ function uniq(array) {
|
|
|
801
918
|
}
|
|
802
919
|
return baseUniq(array);
|
|
803
920
|
}
|
|
921
|
+
|
|
922
|
+
// src/upperCase.ts
|
|
923
|
+
function upperCase(value) {
|
|
924
|
+
return words(value).join(" ").toUpperCase();
|
|
925
|
+
}
|
|
804
926
|
// Annotate the CommonJS export names for ESM import in node:
|
|
805
927
|
0 && (module.exports = {
|
|
806
928
|
addLeadingSlash,
|
|
@@ -816,6 +938,7 @@ function uniq(array) {
|
|
|
816
938
|
flattenDeep,
|
|
817
939
|
forEach,
|
|
818
940
|
get,
|
|
941
|
+
groupBy,
|
|
819
942
|
intersection,
|
|
820
943
|
intersectionBy,
|
|
821
944
|
isArray,
|
|
@@ -834,6 +957,7 @@ function uniq(array) {
|
|
|
834
957
|
isUndefined,
|
|
835
958
|
keys,
|
|
836
959
|
map,
|
|
960
|
+
mapKeys,
|
|
837
961
|
mapValues,
|
|
838
962
|
mapValuesAsync,
|
|
839
963
|
noop,
|
|
@@ -843,10 +967,15 @@ function uniq(array) {
|
|
|
843
967
|
padEnd,
|
|
844
968
|
parseBooleanString,
|
|
845
969
|
pick,
|
|
970
|
+
pickBy,
|
|
846
971
|
reduce,
|
|
847
972
|
removeConsecutiveSlashesFromUrl,
|
|
848
973
|
set,
|
|
974
|
+
startCase,
|
|
975
|
+
sum,
|
|
976
|
+
sumBy,
|
|
849
977
|
toAsyncFn,
|
|
850
978
|
toStringRecord,
|
|
851
|
-
uniq
|
|
979
|
+
uniq,
|
|
980
|
+
upperCase
|
|
852
981
|
});
|
package/index.mjs
CHANGED
|
@@ -24,6 +24,7 @@ function castArray(value) {
|
|
|
24
24
|
|
|
25
25
|
// src/_internal.ts
|
|
26
26
|
var pathPattern = /[^.[\]]+|\[(?:([^"'[\]]+)|["']([^"']+)["'])\]/g;
|
|
27
|
+
var unsafePathParts = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
27
28
|
function isObject(value) {
|
|
28
29
|
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
29
30
|
}
|
|
@@ -56,6 +57,15 @@ function toPath(path) {
|
|
|
56
57
|
});
|
|
57
58
|
return result.length > 0 ? result : [input];
|
|
58
59
|
}
|
|
60
|
+
function hasUnsafePathPart(parts) {
|
|
61
|
+
for (let index = 0; index < parts.length; index++) {
|
|
62
|
+
const part = parts[index];
|
|
63
|
+
if (typeof part === "string" && unsafePathParts.has(part)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
59
69
|
function hasPath(value, path) {
|
|
60
70
|
const parts = toPath(path);
|
|
61
71
|
if (parts.length === 0) {
|
|
@@ -90,7 +100,7 @@ function setPath(target, path, value) {
|
|
|
90
100
|
return target;
|
|
91
101
|
}
|
|
92
102
|
const parts = toPath(path);
|
|
93
|
-
if (parts.length === 0) {
|
|
103
|
+
if (parts.length === 0 || hasUnsafePathPart(parts)) {
|
|
94
104
|
return target;
|
|
95
105
|
}
|
|
96
106
|
let current = target;
|
|
@@ -111,7 +121,7 @@ function deletePath(target, path) {
|
|
|
111
121
|
return;
|
|
112
122
|
}
|
|
113
123
|
const parts = toPath(path);
|
|
114
|
-
if (parts.length === 0) {
|
|
124
|
+
if (parts.length === 0 || hasUnsafePathPart(parts)) {
|
|
115
125
|
return;
|
|
116
126
|
}
|
|
117
127
|
let current = target;
|
|
@@ -157,6 +167,14 @@ function getIteratee(iteratee) {
|
|
|
157
167
|
}
|
|
158
168
|
return (value) => getPath(value, iteratee);
|
|
159
169
|
}
|
|
170
|
+
var wordPattern = /[A-Z]{2,}(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]+|[0-9]+/g;
|
|
171
|
+
function words(value) {
|
|
172
|
+
const input = String(value ?? "");
|
|
173
|
+
if (input.length === 0) {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
return input.replace(/[']/g, "").match(wordPattern) ?? [];
|
|
177
|
+
}
|
|
160
178
|
function compareAscending(left, right) {
|
|
161
179
|
if (sameValueZero(left, right)) {
|
|
162
180
|
return 0;
|
|
@@ -417,6 +435,31 @@ function get(object, path, defaultValue) {
|
|
|
417
435
|
return getPath(object, path, defaultValue);
|
|
418
436
|
}
|
|
419
437
|
|
|
438
|
+
// src/groupBy.ts
|
|
439
|
+
function groupBy(collection, iteratee) {
|
|
440
|
+
if (!collection) {
|
|
441
|
+
return {};
|
|
442
|
+
}
|
|
443
|
+
const callback = getIteratee(iteratee);
|
|
444
|
+
const result = {};
|
|
445
|
+
if (Array.isArray(collection)) {
|
|
446
|
+
for (let index = 0; index < collection.length; index++) {
|
|
447
|
+
const value = collection[index];
|
|
448
|
+
const key = String(callback(value, index, collection));
|
|
449
|
+
(result[key] ??= []).push(value);
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
const keys2 = Object.keys(collection);
|
|
454
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
455
|
+
const key = keys2[index];
|
|
456
|
+
const value = collection[key];
|
|
457
|
+
const group = String(callback(value, key, collection));
|
|
458
|
+
(result[group] ??= []).push(value);
|
|
459
|
+
}
|
|
460
|
+
return result;
|
|
461
|
+
}
|
|
462
|
+
|
|
420
463
|
// src/intersection.ts
|
|
421
464
|
function intersection(...arrays) {
|
|
422
465
|
const [first = [], ...rest] = arrays;
|
|
@@ -570,6 +613,20 @@ function map(collection, iteratee) {
|
|
|
570
613
|
return result;
|
|
571
614
|
}
|
|
572
615
|
|
|
616
|
+
// src/mapKeys.ts
|
|
617
|
+
function mapKeys(object, iteratee) {
|
|
618
|
+
if (!object) {
|
|
619
|
+
return {};
|
|
620
|
+
}
|
|
621
|
+
const result = {};
|
|
622
|
+
const keys2 = Object.keys(object);
|
|
623
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
624
|
+
const key = keys2[index];
|
|
625
|
+
result[String(iteratee(object[key], key, object))] = object[key];
|
|
626
|
+
}
|
|
627
|
+
return result;
|
|
628
|
+
}
|
|
629
|
+
|
|
573
630
|
// src/mapValues.ts
|
|
574
631
|
function mapValues(object, iteratee) {
|
|
575
632
|
if (!object) {
|
|
@@ -655,6 +712,23 @@ function pick(object, paths) {
|
|
|
655
712
|
return result;
|
|
656
713
|
}
|
|
657
714
|
|
|
715
|
+
// src/pickBy.ts
|
|
716
|
+
function pickBy(object, predicate) {
|
|
717
|
+
if (!object) {
|
|
718
|
+
return {};
|
|
719
|
+
}
|
|
720
|
+
const result = {};
|
|
721
|
+
const keys2 = Object.keys(object);
|
|
722
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
723
|
+
const key = keys2[index];
|
|
724
|
+
const value = object[key];
|
|
725
|
+
if (predicate(value, key, object)) {
|
|
726
|
+
result[key] = value;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return result;
|
|
730
|
+
}
|
|
731
|
+
|
|
658
732
|
// src/removeConsecutiveSlashesFromUrl.ts
|
|
659
733
|
function removeConsecutiveSlashesFromUrl(url) {
|
|
660
734
|
return url.replace(/\/{2,}/g, "/");
|
|
@@ -701,6 +775,42 @@ function set(object, path, value) {
|
|
|
701
775
|
return setPath(object, path, value);
|
|
702
776
|
}
|
|
703
777
|
|
|
778
|
+
// src/startCase.ts
|
|
779
|
+
function startCase(value) {
|
|
780
|
+
return words(value).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// src/sum.ts
|
|
784
|
+
function sum(values) {
|
|
785
|
+
if (!Array.isArray(values)) {
|
|
786
|
+
return 0;
|
|
787
|
+
}
|
|
788
|
+
let result = 0;
|
|
789
|
+
for (let index = 0; index < values.length; index++) {
|
|
790
|
+
const value = values[index];
|
|
791
|
+
if (value !== void 0) {
|
|
792
|
+
result += value;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return result;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/sumBy.ts
|
|
799
|
+
function sumBy(collection, iteratee) {
|
|
800
|
+
if (!Array.isArray(collection)) {
|
|
801
|
+
return 0;
|
|
802
|
+
}
|
|
803
|
+
const callback = getIteratee(iteratee);
|
|
804
|
+
let result = 0;
|
|
805
|
+
for (let index = 0; index < collection.length; index++) {
|
|
806
|
+
const current = callback(collection[index], index, collection);
|
|
807
|
+
if (current !== void 0) {
|
|
808
|
+
result += current;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return result;
|
|
812
|
+
}
|
|
813
|
+
|
|
704
814
|
// src/toAsyncFn.ts
|
|
705
815
|
function toAsyncFn(fn, defaultValue) {
|
|
706
816
|
if (!fn) return () => Promise.resolve(defaultValue);
|
|
@@ -731,6 +841,11 @@ function uniq(array) {
|
|
|
731
841
|
}
|
|
732
842
|
return baseUniq(array);
|
|
733
843
|
}
|
|
844
|
+
|
|
845
|
+
// src/upperCase.ts
|
|
846
|
+
function upperCase(value) {
|
|
847
|
+
return words(value).join(" ").toUpperCase();
|
|
848
|
+
}
|
|
734
849
|
export {
|
|
735
850
|
addLeadingSlash,
|
|
736
851
|
arrayToRecord,
|
|
@@ -745,6 +860,7 @@ export {
|
|
|
745
860
|
flattenDeep,
|
|
746
861
|
forEach,
|
|
747
862
|
get,
|
|
863
|
+
groupBy,
|
|
748
864
|
intersection,
|
|
749
865
|
intersectionBy,
|
|
750
866
|
isArray,
|
|
@@ -763,6 +879,7 @@ export {
|
|
|
763
879
|
isUndefined,
|
|
764
880
|
keys,
|
|
765
881
|
map,
|
|
882
|
+
mapKeys,
|
|
766
883
|
mapValues,
|
|
767
884
|
mapValuesAsync,
|
|
768
885
|
noop,
|
|
@@ -772,10 +889,15 @@ export {
|
|
|
772
889
|
padEnd,
|
|
773
890
|
parseBooleanString,
|
|
774
891
|
pick,
|
|
892
|
+
pickBy,
|
|
775
893
|
reduce,
|
|
776
894
|
removeConsecutiveSlashesFromUrl,
|
|
777
895
|
set,
|
|
896
|
+
startCase,
|
|
897
|
+
sum,
|
|
898
|
+
sumBy,
|
|
778
899
|
toAsyncFn,
|
|
779
900
|
toStringRecord,
|
|
780
|
-
uniq
|
|
901
|
+
uniq,
|
|
902
|
+
upperCase
|
|
781
903
|
};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@web-ts-toolkit/utils",
|
|
3
3
|
"description": "Shared collection, object, async, and URL helpers used across workspace packages",
|
|
4
4
|
"homepage": "https://web-ts-toolkit.pages.dev/docs/packages/utils",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.29.0",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"keywords": [
|
|
8
8
|
"utilities",
|