@web-ts-toolkit/utils 0.28.0 → 0.30.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 +34 -6
- package/index.d.mts +21 -1
- package/index.d.ts +21 -1
- package/index.js +184 -4
- package/index.mjs +173 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,8 +10,8 @@ pnpm add @web-ts-toolkit/utils
|
|
|
10
10
|
|
|
11
11
|
## Highlights
|
|
12
12
|
|
|
13
|
-
- object-path helpers such as `get(...)` and `
|
|
14
|
-
- collection helpers such as `map(...)`, `filter(...)`, `uniq(...)`, and `orderBy(...)`
|
|
13
|
+
- object-path helpers such as `get(...)`, `set(...)`, and `hasOwn(...)`
|
|
14
|
+
- collection helpers such as `map(...)`, `filter(...)`, `uniq(...)`, `uniqBy(...)`, and `orderBy(...)`
|
|
15
15
|
- small type guards
|
|
16
16
|
- URL helpers such as `normalizeUrlPath(...)`
|
|
17
17
|
- async helpers such as `mapValuesAsync(...)`
|
|
@@ -19,7 +19,16 @@ pnpm add @web-ts-toolkit/utils
|
|
|
19
19
|
## Quick Start
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
get,
|
|
24
|
+
groupBy,
|
|
25
|
+
hasOwn,
|
|
26
|
+
normalizeUrlPath,
|
|
27
|
+
parseBooleanString,
|
|
28
|
+
startCase,
|
|
29
|
+
sumBy,
|
|
30
|
+
uniqBy,
|
|
31
|
+
} from '@web-ts-toolkit/utils';
|
|
23
32
|
|
|
24
33
|
const payload = {
|
|
25
34
|
user: {
|
|
@@ -30,15 +39,34 @@ const payload = {
|
|
|
30
39
|
};
|
|
31
40
|
|
|
32
41
|
get(payload, 'user.profile.name');
|
|
33
|
-
|
|
42
|
+
hasOwn(payload.user.profile, 'name');
|
|
43
|
+
groupBy(
|
|
44
|
+
[
|
|
45
|
+
{ type: 'fruit', name: 'apple' },
|
|
46
|
+
{ type: 'fruit', name: 'banana' },
|
|
47
|
+
{ type: 'vegetable', name: 'carrot' },
|
|
48
|
+
],
|
|
49
|
+
'type',
|
|
50
|
+
);
|
|
51
|
+
uniqBy(
|
|
52
|
+
[
|
|
53
|
+
{ id: 'a', name: 'Ada' },
|
|
54
|
+
{ id: 'a', name: 'Ada Lovelace' },
|
|
55
|
+
{ id: 'b', name: 'Grace' },
|
|
56
|
+
],
|
|
57
|
+
'id',
|
|
58
|
+
);
|
|
59
|
+
startCase('api_response_time');
|
|
60
|
+
sumBy([{ hours: 2 }, { hours: 3 }], 'hours');
|
|
34
61
|
normalizeUrlPath('api//users');
|
|
35
62
|
parseBooleanString('true', false);
|
|
36
63
|
```
|
|
37
64
|
|
|
38
65
|
## Main Exports
|
|
39
66
|
|
|
40
|
-
- object helpers: `get`, `set`, `pick`, `omit`, `assign`, `cloneDeep`
|
|
41
|
-
- collection helpers: `map`, `filter`, `reduce`, `find`, `flatten`, `uniq`, `orderBy`
|
|
67
|
+
- object helpers: `get`, `set`, `hasOwn`, `pick`, `pickBy`, `omit`, `omitBy`, `assign`, `cloneDeep`, `mapKeys`
|
|
68
|
+
- collection helpers: `map`, `filter`, `reduce`, `find`, `flatten`, `uniq`, `uniqBy`, `orderBy`, `groupBy`, `sum`, `sumBy`
|
|
69
|
+
- string helpers: `startCase`, `upperCase`
|
|
42
70
|
- guards: `isArray`, `isPlainObject`, `isString`, `isPromise`
|
|
43
71
|
- URL helpers: `addLeadingSlash`, `removeConsecutiveSlashesFromUrl`, `normalizeUrlPath`
|
|
44
72
|
|
package/index.d.mts
CHANGED
|
@@ -27,6 +27,10 @@ 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
|
+
|
|
32
|
+
declare function hasOwn<TKey extends PropertyKey>(value: unknown, key: TKey): value is Record<TKey, unknown>;
|
|
33
|
+
|
|
30
34
|
declare function intersection<T>(...arrays: Array<T[] | null | undefined>): T[];
|
|
31
35
|
|
|
32
36
|
declare function intersectionBy<T>(...args: unknown[]): T[];
|
|
@@ -63,6 +67,8 @@ declare function keys(value: unknown): string[];
|
|
|
63
67
|
|
|
64
68
|
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
69
|
|
|
70
|
+
declare function mapKeys<TValue>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => string): Record<string, TValue>;
|
|
71
|
+
|
|
66
72
|
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
73
|
|
|
68
74
|
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>>;
|
|
@@ -71,6 +77,8 @@ declare function noop(): void;
|
|
|
71
77
|
|
|
72
78
|
declare function omit<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
73
79
|
|
|
80
|
+
declare function omitBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
81
|
+
|
|
74
82
|
declare function parseBooleanString(str: string | undefined, defaultValue?: boolean): boolean | undefined;
|
|
75
83
|
|
|
76
84
|
declare function orderBy<T>(collection: T[] | null | undefined, iteratees?: Array<string | number | ((value: T) => unknown)>, orders?: string[]): T[];
|
|
@@ -79,6 +87,8 @@ declare function padEnd(value: unknown, length?: number, chars?: string): string
|
|
|
79
87
|
|
|
80
88
|
declare function pick<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
81
89
|
|
|
90
|
+
declare function pickBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
91
|
+
|
|
82
92
|
declare function normalizeUrlPath(url: string): string;
|
|
83
93
|
|
|
84
94
|
declare function reduce<T, TResult>(collection: T[] | null | undefined, iteratee: (accumulator: TResult, value: T, key: number, collection: T[]) => TResult, accumulator?: TResult): TResult;
|
|
@@ -88,10 +98,20 @@ declare function removeConsecutiveSlashesFromUrl(url: string): string;
|
|
|
88
98
|
|
|
89
99
|
declare function set<T>(object: T, path: PropertyPath, value: unknown): T;
|
|
90
100
|
|
|
101
|
+
declare function startCase(value: unknown): string;
|
|
102
|
+
|
|
103
|
+
declare function sum(values: number[] | null | undefined): number;
|
|
104
|
+
|
|
105
|
+
declare function sumBy<T>(collection: T[] | null | undefined, iteratee: string | number | ((value: T, key: number, collection: T[]) => number | undefined)): number;
|
|
106
|
+
|
|
91
107
|
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
108
|
|
|
93
109
|
declare function toStringRecord(value: unknown): Record<string, string> | undefined;
|
|
94
110
|
|
|
95
111
|
declare function uniq<T>(array: T[] | null | undefined): T[];
|
|
96
112
|
|
|
97
|
-
|
|
113
|
+
declare function uniqBy<T>(array: T[] | null | undefined, iteratee?: string | number | ((value: T, key: number, collection: T[]) => unknown)): T[];
|
|
114
|
+
|
|
115
|
+
declare function upperCase(value: unknown): string;
|
|
116
|
+
|
|
117
|
+
export { addLeadingSlash, arrayToRecord, assign, castArray, cloneDeep, compact, difference, filter, find, flatten, flattenDeep, forEach, get, groupBy, hasOwn, 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, omitBy, orderBy, padEnd, parseBooleanString, pick, pickBy, reduce, removeConsecutiveSlashesFromUrl, set, startCase, sum, sumBy, toAsyncFn, toStringRecord, uniq, uniqBy, upperCase };
|
package/index.d.ts
CHANGED
|
@@ -27,6 +27,10 @@ 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
|
+
|
|
32
|
+
declare function hasOwn<TKey extends PropertyKey>(value: unknown, key: TKey): value is Record<TKey, unknown>;
|
|
33
|
+
|
|
30
34
|
declare function intersection<T>(...arrays: Array<T[] | null | undefined>): T[];
|
|
31
35
|
|
|
32
36
|
declare function intersectionBy<T>(...args: unknown[]): T[];
|
|
@@ -63,6 +67,8 @@ declare function keys(value: unknown): string[];
|
|
|
63
67
|
|
|
64
68
|
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
69
|
|
|
70
|
+
declare function mapKeys<TValue>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => string): Record<string, TValue>;
|
|
71
|
+
|
|
66
72
|
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
73
|
|
|
68
74
|
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>>;
|
|
@@ -71,6 +77,8 @@ declare function noop(): void;
|
|
|
71
77
|
|
|
72
78
|
declare function omit<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
73
79
|
|
|
80
|
+
declare function omitBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
81
|
+
|
|
74
82
|
declare function parseBooleanString(str: string | undefined, defaultValue?: boolean): boolean | undefined;
|
|
75
83
|
|
|
76
84
|
declare function orderBy<T>(collection: T[] | null | undefined, iteratees?: Array<string | number | ((value: T) => unknown)>, orders?: string[]): T[];
|
|
@@ -79,6 +87,8 @@ declare function padEnd(value: unknown, length?: number, chars?: string): string
|
|
|
79
87
|
|
|
80
88
|
declare function pick<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
81
89
|
|
|
90
|
+
declare function pickBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
91
|
+
|
|
82
92
|
declare function normalizeUrlPath(url: string): string;
|
|
83
93
|
|
|
84
94
|
declare function reduce<T, TResult>(collection: T[] | null | undefined, iteratee: (accumulator: TResult, value: T, key: number, collection: T[]) => TResult, accumulator?: TResult): TResult;
|
|
@@ -88,10 +98,20 @@ declare function removeConsecutiveSlashesFromUrl(url: string): string;
|
|
|
88
98
|
|
|
89
99
|
declare function set<T>(object: T, path: PropertyPath, value: unknown): T;
|
|
90
100
|
|
|
101
|
+
declare function startCase(value: unknown): string;
|
|
102
|
+
|
|
103
|
+
declare function sum(values: number[] | null | undefined): number;
|
|
104
|
+
|
|
105
|
+
declare function sumBy<T>(collection: T[] | null | undefined, iteratee: string | number | ((value: T, key: number, collection: T[]) => number | undefined)): number;
|
|
106
|
+
|
|
91
107
|
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
108
|
|
|
93
109
|
declare function toStringRecord(value: unknown): Record<string, string> | undefined;
|
|
94
110
|
|
|
95
111
|
declare function uniq<T>(array: T[] | null | undefined): T[];
|
|
96
112
|
|
|
97
|
-
|
|
113
|
+
declare function uniqBy<T>(array: T[] | null | undefined, iteratee?: string | number | ((value: T, key: number, collection: T[]) => unknown)): T[];
|
|
114
|
+
|
|
115
|
+
declare function upperCase(value: unknown): string;
|
|
116
|
+
|
|
117
|
+
export { addLeadingSlash, arrayToRecord, assign, castArray, cloneDeep, compact, difference, filter, find, flatten, flattenDeep, forEach, get, groupBy, hasOwn, 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, omitBy, orderBy, padEnd, parseBooleanString, pick, pickBy, reduce, removeConsecutiveSlashesFromUrl, set, startCase, sum, sumBy, toAsyncFn, toStringRecord, uniq, uniqBy, upperCase };
|
package/index.js
CHANGED
|
@@ -32,6 +32,8 @@ __export(index_exports, {
|
|
|
32
32
|
flattenDeep: () => flattenDeep,
|
|
33
33
|
forEach: () => forEach,
|
|
34
34
|
get: () => get,
|
|
35
|
+
groupBy: () => groupBy,
|
|
36
|
+
hasOwn: () => hasOwn,
|
|
35
37
|
intersection: () => intersection,
|
|
36
38
|
intersectionBy: () => intersectionBy,
|
|
37
39
|
isArray: () => isArray,
|
|
@@ -50,21 +52,29 @@ __export(index_exports, {
|
|
|
50
52
|
isUndefined: () => isUndefined,
|
|
51
53
|
keys: () => keys,
|
|
52
54
|
map: () => map,
|
|
55
|
+
mapKeys: () => mapKeys,
|
|
53
56
|
mapValues: () => mapValues,
|
|
54
57
|
mapValuesAsync: () => mapValuesAsync,
|
|
55
58
|
noop: () => noop,
|
|
56
59
|
normalizeUrlPath: () => normalizeUrlPath,
|
|
57
60
|
omit: () => omit,
|
|
61
|
+
omitBy: () => omitBy,
|
|
58
62
|
orderBy: () => orderBy,
|
|
59
63
|
padEnd: () => padEnd,
|
|
60
64
|
parseBooleanString: () => parseBooleanString,
|
|
61
65
|
pick: () => pick,
|
|
66
|
+
pickBy: () => pickBy,
|
|
62
67
|
reduce: () => reduce,
|
|
63
68
|
removeConsecutiveSlashesFromUrl: () => removeConsecutiveSlashesFromUrl,
|
|
64
69
|
set: () => set,
|
|
70
|
+
startCase: () => startCase,
|
|
71
|
+
sum: () => sum,
|
|
72
|
+
sumBy: () => sumBy,
|
|
65
73
|
toAsyncFn: () => toAsyncFn,
|
|
66
74
|
toStringRecord: () => toStringRecord,
|
|
67
|
-
uniq: () => uniq
|
|
75
|
+
uniq: () => uniq,
|
|
76
|
+
uniqBy: () => uniqBy,
|
|
77
|
+
upperCase: () => upperCase
|
|
68
78
|
});
|
|
69
79
|
module.exports = __toCommonJS(index_exports);
|
|
70
80
|
|
|
@@ -94,6 +104,7 @@ function castArray(value) {
|
|
|
94
104
|
|
|
95
105
|
// src/_internal.ts
|
|
96
106
|
var pathPattern = /[^.[\]]+|\[(?:([^"'[\]]+)|["']([^"']+)["'])\]/g;
|
|
107
|
+
var unsafePathParts = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
97
108
|
function isObject(value) {
|
|
98
109
|
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
99
110
|
}
|
|
@@ -126,6 +137,15 @@ function toPath(path) {
|
|
|
126
137
|
});
|
|
127
138
|
return result.length > 0 ? result : [input];
|
|
128
139
|
}
|
|
140
|
+
function hasUnsafePathPart(parts) {
|
|
141
|
+
for (let index = 0; index < parts.length; index++) {
|
|
142
|
+
const part = parts[index];
|
|
143
|
+
if (typeof part === "string" && unsafePathParts.has(part)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
129
149
|
function hasPath(value, path) {
|
|
130
150
|
const parts = toPath(path);
|
|
131
151
|
if (parts.length === 0) {
|
|
@@ -160,7 +180,7 @@ function setPath(target, path, value) {
|
|
|
160
180
|
return target;
|
|
161
181
|
}
|
|
162
182
|
const parts = toPath(path);
|
|
163
|
-
if (parts.length === 0) {
|
|
183
|
+
if (parts.length === 0 || hasUnsafePathPart(parts)) {
|
|
164
184
|
return target;
|
|
165
185
|
}
|
|
166
186
|
let current = target;
|
|
@@ -181,7 +201,7 @@ function deletePath(target, path) {
|
|
|
181
201
|
return;
|
|
182
202
|
}
|
|
183
203
|
const parts = toPath(path);
|
|
184
|
-
if (parts.length === 0) {
|
|
204
|
+
if (parts.length === 0 || hasUnsafePathPart(parts)) {
|
|
185
205
|
return;
|
|
186
206
|
}
|
|
187
207
|
let current = target;
|
|
@@ -227,6 +247,14 @@ function getIteratee(iteratee) {
|
|
|
227
247
|
}
|
|
228
248
|
return (value) => getPath(value, iteratee);
|
|
229
249
|
}
|
|
250
|
+
var wordPattern = /[A-Z]{2,}(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]+|[0-9]+/g;
|
|
251
|
+
function words(value) {
|
|
252
|
+
const input = String(value ?? "");
|
|
253
|
+
if (input.length === 0) {
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
return input.replace(/[']/g, "").match(wordPattern) ?? [];
|
|
257
|
+
}
|
|
230
258
|
function compareAscending(left, right) {
|
|
231
259
|
if (sameValueZero(left, right)) {
|
|
232
260
|
return 0;
|
|
@@ -487,6 +515,39 @@ function get(object, path, defaultValue) {
|
|
|
487
515
|
return getPath(object, path, defaultValue);
|
|
488
516
|
}
|
|
489
517
|
|
|
518
|
+
// src/groupBy.ts
|
|
519
|
+
function groupBy(collection, iteratee) {
|
|
520
|
+
if (!collection) {
|
|
521
|
+
return {};
|
|
522
|
+
}
|
|
523
|
+
const callback = getIteratee(iteratee);
|
|
524
|
+
const result = {};
|
|
525
|
+
if (Array.isArray(collection)) {
|
|
526
|
+
for (let index = 0; index < collection.length; index++) {
|
|
527
|
+
const value = collection[index];
|
|
528
|
+
const key = String(callback(value, index, collection));
|
|
529
|
+
(result[key] ??= []).push(value);
|
|
530
|
+
}
|
|
531
|
+
return result;
|
|
532
|
+
}
|
|
533
|
+
const keys2 = Object.keys(collection);
|
|
534
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
535
|
+
const key = keys2[index];
|
|
536
|
+
const value = collection[key];
|
|
537
|
+
const group = String(callback(value, key, collection));
|
|
538
|
+
(result[group] ??= []).push(value);
|
|
539
|
+
}
|
|
540
|
+
return result;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/hasOwn.ts
|
|
544
|
+
function hasOwn(value, key) {
|
|
545
|
+
if (value === null || value === void 0) {
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
return Object.hasOwn(Object(value), key);
|
|
549
|
+
}
|
|
550
|
+
|
|
490
551
|
// src/intersection.ts
|
|
491
552
|
function intersection(...arrays) {
|
|
492
553
|
const [first = [], ...rest] = arrays;
|
|
@@ -640,6 +701,20 @@ function map(collection, iteratee) {
|
|
|
640
701
|
return result;
|
|
641
702
|
}
|
|
642
703
|
|
|
704
|
+
// src/mapKeys.ts
|
|
705
|
+
function mapKeys(object, iteratee) {
|
|
706
|
+
if (!object) {
|
|
707
|
+
return {};
|
|
708
|
+
}
|
|
709
|
+
const result = {};
|
|
710
|
+
const keys2 = Object.keys(object);
|
|
711
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
712
|
+
const key = keys2[index];
|
|
713
|
+
result[String(iteratee(object[key], key, object))] = object[key];
|
|
714
|
+
}
|
|
715
|
+
return result;
|
|
716
|
+
}
|
|
717
|
+
|
|
643
718
|
// src/mapValues.ts
|
|
644
719
|
function mapValues(object, iteratee) {
|
|
645
720
|
if (!object) {
|
|
@@ -680,6 +755,23 @@ function omit(object, paths) {
|
|
|
680
755
|
return result;
|
|
681
756
|
}
|
|
682
757
|
|
|
758
|
+
// src/omitBy.ts
|
|
759
|
+
function omitBy(object, predicate) {
|
|
760
|
+
if (!object) {
|
|
761
|
+
return {};
|
|
762
|
+
}
|
|
763
|
+
const result = {};
|
|
764
|
+
const keys2 = Object.keys(object);
|
|
765
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
766
|
+
const key = keys2[index];
|
|
767
|
+
const value = object[key];
|
|
768
|
+
if (!predicate(value, key, object)) {
|
|
769
|
+
result[key] = value;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return result;
|
|
773
|
+
}
|
|
774
|
+
|
|
683
775
|
// src/parseBooleanString.ts
|
|
684
776
|
function parseBooleanString(str, defaultValue) {
|
|
685
777
|
return str ? str === "true" : defaultValue;
|
|
@@ -725,6 +817,23 @@ function pick(object, paths) {
|
|
|
725
817
|
return result;
|
|
726
818
|
}
|
|
727
819
|
|
|
820
|
+
// src/pickBy.ts
|
|
821
|
+
function pickBy(object, predicate) {
|
|
822
|
+
if (!object) {
|
|
823
|
+
return {};
|
|
824
|
+
}
|
|
825
|
+
const result = {};
|
|
826
|
+
const keys2 = Object.keys(object);
|
|
827
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
828
|
+
const key = keys2[index];
|
|
829
|
+
const value = object[key];
|
|
830
|
+
if (predicate(value, key, object)) {
|
|
831
|
+
result[key] = value;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return result;
|
|
835
|
+
}
|
|
836
|
+
|
|
728
837
|
// src/removeConsecutiveSlashesFromUrl.ts
|
|
729
838
|
function removeConsecutiveSlashesFromUrl(url) {
|
|
730
839
|
return url.replace(/\/{2,}/g, "/");
|
|
@@ -771,6 +880,42 @@ function set(object, path, value) {
|
|
|
771
880
|
return setPath(object, path, value);
|
|
772
881
|
}
|
|
773
882
|
|
|
883
|
+
// src/startCase.ts
|
|
884
|
+
function startCase(value) {
|
|
885
|
+
return words(value).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// src/sum.ts
|
|
889
|
+
function sum(values) {
|
|
890
|
+
if (!Array.isArray(values)) {
|
|
891
|
+
return 0;
|
|
892
|
+
}
|
|
893
|
+
let result = 0;
|
|
894
|
+
for (let index = 0; index < values.length; index++) {
|
|
895
|
+
const value = values[index];
|
|
896
|
+
if (value !== void 0) {
|
|
897
|
+
result += value;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
return result;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// src/sumBy.ts
|
|
904
|
+
function sumBy(collection, iteratee) {
|
|
905
|
+
if (!Array.isArray(collection)) {
|
|
906
|
+
return 0;
|
|
907
|
+
}
|
|
908
|
+
const callback = getIteratee(iteratee);
|
|
909
|
+
let result = 0;
|
|
910
|
+
for (let index = 0; index < collection.length; index++) {
|
|
911
|
+
const current = callback(collection[index], index, collection);
|
|
912
|
+
if (current !== void 0) {
|
|
913
|
+
result += current;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
return result;
|
|
917
|
+
}
|
|
918
|
+
|
|
774
919
|
// src/toAsyncFn.ts
|
|
775
920
|
function toAsyncFn(fn, defaultValue) {
|
|
776
921
|
if (!fn) return () => Promise.resolve(defaultValue);
|
|
@@ -801,6 +946,31 @@ function uniq(array) {
|
|
|
801
946
|
}
|
|
802
947
|
return baseUniq(array);
|
|
803
948
|
}
|
|
949
|
+
|
|
950
|
+
// src/uniqBy.ts
|
|
951
|
+
function uniqBy(array, iteratee) {
|
|
952
|
+
if (!Array.isArray(array)) {
|
|
953
|
+
return [];
|
|
954
|
+
}
|
|
955
|
+
const callback = getIteratee(iteratee);
|
|
956
|
+
const result = [];
|
|
957
|
+
const seen = [];
|
|
958
|
+
for (let index = 0; index < array.length; index++) {
|
|
959
|
+
const value = array[index];
|
|
960
|
+
const computed = callback(value, index, array);
|
|
961
|
+
if (seen.some((entry) => sameValueZero(entry, computed))) {
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
964
|
+
seen.push(computed);
|
|
965
|
+
result.push(value);
|
|
966
|
+
}
|
|
967
|
+
return result;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/upperCase.ts
|
|
971
|
+
function upperCase(value) {
|
|
972
|
+
return words(value).join(" ").toUpperCase();
|
|
973
|
+
}
|
|
804
974
|
// Annotate the CommonJS export names for ESM import in node:
|
|
805
975
|
0 && (module.exports = {
|
|
806
976
|
addLeadingSlash,
|
|
@@ -816,6 +986,8 @@ function uniq(array) {
|
|
|
816
986
|
flattenDeep,
|
|
817
987
|
forEach,
|
|
818
988
|
get,
|
|
989
|
+
groupBy,
|
|
990
|
+
hasOwn,
|
|
819
991
|
intersection,
|
|
820
992
|
intersectionBy,
|
|
821
993
|
isArray,
|
|
@@ -834,19 +1006,27 @@ function uniq(array) {
|
|
|
834
1006
|
isUndefined,
|
|
835
1007
|
keys,
|
|
836
1008
|
map,
|
|
1009
|
+
mapKeys,
|
|
837
1010
|
mapValues,
|
|
838
1011
|
mapValuesAsync,
|
|
839
1012
|
noop,
|
|
840
1013
|
normalizeUrlPath,
|
|
841
1014
|
omit,
|
|
1015
|
+
omitBy,
|
|
842
1016
|
orderBy,
|
|
843
1017
|
padEnd,
|
|
844
1018
|
parseBooleanString,
|
|
845
1019
|
pick,
|
|
1020
|
+
pickBy,
|
|
846
1021
|
reduce,
|
|
847
1022
|
removeConsecutiveSlashesFromUrl,
|
|
848
1023
|
set,
|
|
1024
|
+
startCase,
|
|
1025
|
+
sum,
|
|
1026
|
+
sumBy,
|
|
849
1027
|
toAsyncFn,
|
|
850
1028
|
toStringRecord,
|
|
851
|
-
uniq
|
|
1029
|
+
uniq,
|
|
1030
|
+
uniqBy,
|
|
1031
|
+
upperCase
|
|
852
1032
|
});
|
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,39 @@ 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
|
+
|
|
463
|
+
// src/hasOwn.ts
|
|
464
|
+
function hasOwn(value, key) {
|
|
465
|
+
if (value === null || value === void 0) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
return Object.hasOwn(Object(value), key);
|
|
469
|
+
}
|
|
470
|
+
|
|
420
471
|
// src/intersection.ts
|
|
421
472
|
function intersection(...arrays) {
|
|
422
473
|
const [first = [], ...rest] = arrays;
|
|
@@ -570,6 +621,20 @@ function map(collection, iteratee) {
|
|
|
570
621
|
return result;
|
|
571
622
|
}
|
|
572
623
|
|
|
624
|
+
// src/mapKeys.ts
|
|
625
|
+
function mapKeys(object, iteratee) {
|
|
626
|
+
if (!object) {
|
|
627
|
+
return {};
|
|
628
|
+
}
|
|
629
|
+
const result = {};
|
|
630
|
+
const keys2 = Object.keys(object);
|
|
631
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
632
|
+
const key = keys2[index];
|
|
633
|
+
result[String(iteratee(object[key], key, object))] = object[key];
|
|
634
|
+
}
|
|
635
|
+
return result;
|
|
636
|
+
}
|
|
637
|
+
|
|
573
638
|
// src/mapValues.ts
|
|
574
639
|
function mapValues(object, iteratee) {
|
|
575
640
|
if (!object) {
|
|
@@ -610,6 +675,23 @@ function omit(object, paths) {
|
|
|
610
675
|
return result;
|
|
611
676
|
}
|
|
612
677
|
|
|
678
|
+
// src/omitBy.ts
|
|
679
|
+
function omitBy(object, predicate) {
|
|
680
|
+
if (!object) {
|
|
681
|
+
return {};
|
|
682
|
+
}
|
|
683
|
+
const result = {};
|
|
684
|
+
const keys2 = Object.keys(object);
|
|
685
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
686
|
+
const key = keys2[index];
|
|
687
|
+
const value = object[key];
|
|
688
|
+
if (!predicate(value, key, object)) {
|
|
689
|
+
result[key] = value;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return result;
|
|
693
|
+
}
|
|
694
|
+
|
|
613
695
|
// src/parseBooleanString.ts
|
|
614
696
|
function parseBooleanString(str, defaultValue) {
|
|
615
697
|
return str ? str === "true" : defaultValue;
|
|
@@ -655,6 +737,23 @@ function pick(object, paths) {
|
|
|
655
737
|
return result;
|
|
656
738
|
}
|
|
657
739
|
|
|
740
|
+
// src/pickBy.ts
|
|
741
|
+
function pickBy(object, predicate) {
|
|
742
|
+
if (!object) {
|
|
743
|
+
return {};
|
|
744
|
+
}
|
|
745
|
+
const result = {};
|
|
746
|
+
const keys2 = Object.keys(object);
|
|
747
|
+
for (let index = 0; index < keys2.length; index++) {
|
|
748
|
+
const key = keys2[index];
|
|
749
|
+
const value = object[key];
|
|
750
|
+
if (predicate(value, key, object)) {
|
|
751
|
+
result[key] = value;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return result;
|
|
755
|
+
}
|
|
756
|
+
|
|
658
757
|
// src/removeConsecutiveSlashesFromUrl.ts
|
|
659
758
|
function removeConsecutiveSlashesFromUrl(url) {
|
|
660
759
|
return url.replace(/\/{2,}/g, "/");
|
|
@@ -701,6 +800,42 @@ function set(object, path, value) {
|
|
|
701
800
|
return setPath(object, path, value);
|
|
702
801
|
}
|
|
703
802
|
|
|
803
|
+
// src/startCase.ts
|
|
804
|
+
function startCase(value) {
|
|
805
|
+
return words(value).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// src/sum.ts
|
|
809
|
+
function sum(values) {
|
|
810
|
+
if (!Array.isArray(values)) {
|
|
811
|
+
return 0;
|
|
812
|
+
}
|
|
813
|
+
let result = 0;
|
|
814
|
+
for (let index = 0; index < values.length; index++) {
|
|
815
|
+
const value = values[index];
|
|
816
|
+
if (value !== void 0) {
|
|
817
|
+
result += value;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return result;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/sumBy.ts
|
|
824
|
+
function sumBy(collection, iteratee) {
|
|
825
|
+
if (!Array.isArray(collection)) {
|
|
826
|
+
return 0;
|
|
827
|
+
}
|
|
828
|
+
const callback = getIteratee(iteratee);
|
|
829
|
+
let result = 0;
|
|
830
|
+
for (let index = 0; index < collection.length; index++) {
|
|
831
|
+
const current = callback(collection[index], index, collection);
|
|
832
|
+
if (current !== void 0) {
|
|
833
|
+
result += current;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return result;
|
|
837
|
+
}
|
|
838
|
+
|
|
704
839
|
// src/toAsyncFn.ts
|
|
705
840
|
function toAsyncFn(fn, defaultValue) {
|
|
706
841
|
if (!fn) return () => Promise.resolve(defaultValue);
|
|
@@ -731,6 +866,31 @@ function uniq(array) {
|
|
|
731
866
|
}
|
|
732
867
|
return baseUniq(array);
|
|
733
868
|
}
|
|
869
|
+
|
|
870
|
+
// src/uniqBy.ts
|
|
871
|
+
function uniqBy(array, iteratee) {
|
|
872
|
+
if (!Array.isArray(array)) {
|
|
873
|
+
return [];
|
|
874
|
+
}
|
|
875
|
+
const callback = getIteratee(iteratee);
|
|
876
|
+
const result = [];
|
|
877
|
+
const seen = [];
|
|
878
|
+
for (let index = 0; index < array.length; index++) {
|
|
879
|
+
const value = array[index];
|
|
880
|
+
const computed = callback(value, index, array);
|
|
881
|
+
if (seen.some((entry) => sameValueZero(entry, computed))) {
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
seen.push(computed);
|
|
885
|
+
result.push(value);
|
|
886
|
+
}
|
|
887
|
+
return result;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// src/upperCase.ts
|
|
891
|
+
function upperCase(value) {
|
|
892
|
+
return words(value).join(" ").toUpperCase();
|
|
893
|
+
}
|
|
734
894
|
export {
|
|
735
895
|
addLeadingSlash,
|
|
736
896
|
arrayToRecord,
|
|
@@ -745,6 +905,8 @@ export {
|
|
|
745
905
|
flattenDeep,
|
|
746
906
|
forEach,
|
|
747
907
|
get,
|
|
908
|
+
groupBy,
|
|
909
|
+
hasOwn,
|
|
748
910
|
intersection,
|
|
749
911
|
intersectionBy,
|
|
750
912
|
isArray,
|
|
@@ -763,19 +925,27 @@ export {
|
|
|
763
925
|
isUndefined,
|
|
764
926
|
keys,
|
|
765
927
|
map,
|
|
928
|
+
mapKeys,
|
|
766
929
|
mapValues,
|
|
767
930
|
mapValuesAsync,
|
|
768
931
|
noop,
|
|
769
932
|
normalizeUrlPath,
|
|
770
933
|
omit,
|
|
934
|
+
omitBy,
|
|
771
935
|
orderBy,
|
|
772
936
|
padEnd,
|
|
773
937
|
parseBooleanString,
|
|
774
938
|
pick,
|
|
939
|
+
pickBy,
|
|
775
940
|
reduce,
|
|
776
941
|
removeConsecutiveSlashesFromUrl,
|
|
777
942
|
set,
|
|
943
|
+
startCase,
|
|
944
|
+
sum,
|
|
945
|
+
sumBy,
|
|
778
946
|
toAsyncFn,
|
|
779
947
|
toStringRecord,
|
|
780
|
-
uniq
|
|
948
|
+
uniq,
|
|
949
|
+
uniqBy,
|
|
950
|
+
upperCase
|
|
781
951
|
};
|
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.30.0",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"keywords": [
|
|
8
8
|
"utilities",
|