@helpers4/object 2.0.0-alpha.9 → 2.0.0-beta.3

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 CHANGED
@@ -12,12 +12,20 @@ A set of helpers for working with URLs.
12
12
  [https://helpers4.dev/typescript/categories/object/](https://helpers4.dev/typescript/categories/object/)
13
13
 
14
14
  <!-- AUTOMATIC-METHODS -->
15
+ - compact
15
16
  - deepClone
16
- - deepCompare
17
17
  - deepMerge
18
+ - diff
19
+ - equalsDeep
20
+ - equalsShallow
18
21
  - get
19
- - quickCompare
22
+ - groupBy
23
+ - invert
24
+ - map
25
+ - omit
26
+ - pick
20
27
  - removeUndefinedNull
28
+ - safeJsonParse
21
29
  - set
22
30
  <!-- /AUTOMATIC-METHODS -->
23
31
 
@@ -25,9 +33,12 @@ A set of helpers for working with URLs.
25
33
 
26
34
  <!-- AUTOMATIC-SIBLINGS -->
27
35
  - [array](../array)
36
+ - [ci](../ci)
37
+ - [commit](../commit)
28
38
  - [date](../date)
29
39
  - [function](../function)
30
- - [math](../math)
40
+ - [id](../id)
41
+ - [markdown](../markdown)
31
42
  - [number](../number)
32
43
  - [observable](../observable)
33
44
  - [promise](../promise)
@@ -43,15 +54,18 @@ A set of helpers for working with URLs.
43
54
  | Name | Package | Source Code | Description |
44
55
  |------|---------|-------------|-------------|
45
56
  | array | [@helpers4/array](https://www.npmjs.com/package/@helpers4/array) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/array) | Array manipulation utilities |
46
- | date | [@helpers4/date](https://www.npmjs.com/package/@helpers4/date) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/date) | date utilities |
57
+ | ci | [@helpers4/ci](https://www.npmjs.com/package/@helpers4/ci) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/ci) | CI/CD workflow status utilities |
58
+ | commit | [@helpers4/commit](https://www.npmjs.com/package/@helpers4/commit) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/commit) | Conventional Commits parsing and analysis |
59
+ | date | [@helpers4/date](https://www.npmjs.com/package/@helpers4/date) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/date) | Date and time utility functions |
47
60
  | function | [@helpers4/function](https://www.npmjs.com/package/@helpers4/function) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/function) | Function utilities and type guards |
48
- | math | [@helpers4/math](https://www.npmjs.com/package/@helpers4/math) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/math) | math utilities |
49
- | number | [@helpers4/number](https://www.npmjs.com/package/@helpers4/number) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/number) | number utilities |
61
+ | id | [@helpers4/id](https://www.npmjs.com/package/@helpers4/id) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/id) | Unique identifier generation utilities |
62
+ | markdown | [@helpers4/markdown](https://www.npmjs.com/package/@helpers4/markdown) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/markdown) | Markdown formatting and escaping utilities |
63
+ | number | [@helpers4/number](https://www.npmjs.com/package/@helpers4/number) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/number) | Number utility functions and validation |
50
64
  | object | [@helpers4/object](https://www.npmjs.com/package/@helpers4/object) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/object) | Object manipulation utilities |
51
65
  | observable | [@helpers4/observable](https://www.npmjs.com/package/@helpers4/observable) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/observable) | Observable utilities and combinators |
52
66
  | promise | [@helpers4/promise](https://www.npmjs.com/package/@helpers4/promise) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/promise) | Promise utilities and error handling |
53
67
  | string | [@helpers4/string](https://www.npmjs.com/package/@helpers4/string) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/string) | String manipulation and formatting utilities |
54
- | type | [@helpers4/type](https://www.npmjs.com/package/@helpers4/type) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/type) | type utilities |
68
+ | type | [@helpers4/type](https://www.npmjs.com/package/@helpers4/type) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/type) | Type checking and validation utilities |
55
69
  | url | [@helpers4/url](https://www.npmjs.com/package/@helpers4/url) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/url) | URL parsing and manipulation utilities |
56
70
  | version | [@helpers4/version](https://www.npmjs.com/package/@helpers4/version) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/version) | Version string manipulation utilities |
57
71
  <!-- /AUTOMATIC-CATEGORIES-TABLE -->
package/lib/index.d.ts CHANGED
@@ -1,3 +1,21 @@
1
+ /**
2
+ * This file is part of helpers4.
3
+ * Copyright (C) 2025 baxyz
4
+ * SPDX-License-Identifier: LGPL-3.0-or-later
5
+ */
6
+ /**
7
+ * Removes all entries with falsy values (`false`, `null`, `undefined`, `0`, `""`, `NaN`) from an object.
8
+ * @param obj - The source object
9
+ * @returns A new object containing only entries with truthy values
10
+ * @example
11
+ * compact({ a: 1, b: null, c: '', d: 0, e: 'hello' })
12
+ * // => { a: 1, e: 'hello' }
13
+ * @since 2.0.0
14
+ */
15
+ declare function compact<T extends Record<string, unknown>>(obj: T): Partial<T>;
16
+ declare function compact(obj: undefined): undefined;
17
+ declare function compact(obj: null): null;
18
+
1
19
  /**
2
20
  * This file is part of helpers4.
3
21
  * Copyright (C) 2025 baxyz
@@ -17,21 +35,78 @@ declare function deepClone<T>(obj: T): T;
17
35
  * SPDX-License-Identifier: LGPL-3.0-or-later
18
36
  */
19
37
  /**
20
- * Result type for deep comparison when objects are not identical
38
+ * Merges two or more objects deeply
39
+ * @param target - The target object
40
+ * @param sources - The source objects to merge
41
+ * @returns The merged object
42
+ * @since 1.9.0
43
+ */
44
+ declare function deepMerge<T extends Record<string, unknown>>(target: T, ...sources: Record<string, unknown>[]): T;
45
+ declare function deepMerge(target: undefined, ...sources: Record<string, unknown>[]): undefined;
46
+ declare function deepMerge(target: null, ...sources: Record<string, unknown>[]): null;
47
+
48
+ /**
49
+ * This file is part of helpers4.
50
+ * Copyright (C) 2025 baxyz
51
+ * SPDX-License-Identifier: LGPL-3.0-or-later
52
+ */
53
+ /**
54
+ * Per-key diff result. Each entry tells what differs between the two
55
+ * objects:
56
+ * - `"onlyA"` \u2014 the key exists only on the first input.
57
+ * - `"onlyB"` \u2014 the key exists only on the second input.
58
+ * - `false` \u2014 both inputs have the key but the values differ.
59
+ * - nested `DiffResult` \u2014 plain-object values that differ deeper.
60
+ *
61
+ * @since 2.0.0
62
+ */
63
+ interface DiffResult {
64
+ [key: string]: 'onlyA' | 'onlyB' | false | DiffResult;
65
+ }
66
+ /**
67
+ * Options for {@link diff}.
21
68
  * @since 2.0.0
22
69
  */
23
- interface DeepCompareResult {
24
- [key: string]: "onlyA" | "onlyB" | false | DeepCompareResult;
70
+ interface DiffOptions {
71
+ /**
72
+ * Maximum recursion depth for nested plain objects. Defaults to
73
+ * `Infinity` (full structural diff).
74
+ *
75
+ * - `0` compares values at the top-level only with strict equality.
76
+ * - `1` compares the first level of nested objects with strict equality.
77
+ * - `Infinity` recurses through every plain-object level.
78
+ *
79
+ * Arrays, `Date` and special objects (Map, Set, RegExp\u2026) are always
80
+ * leaf-compared (via {@link arrayDeepEquals}, epoch comparison, or
81
+ * reference equality respectively) regardless of `depth`.
82
+ */
83
+ depth?: number;
25
84
  }
26
85
  /**
27
- * Deep comparison of two objects that returns detailed information about differences.
86
+ * Structural object diff.
87
+ *
88
+ * Returns `true` when both inputs are deeply equal, otherwise a
89
+ * {@link DiffResult} describing the differences key by key.
90
+ *
91
+ * Comparison rules:
92
+ * - Same reference \u2192 `true`.
93
+ * - Either side is `null`/`undefined` (and not both) \u2192 `false`.
94
+ * - Both `Date` \u2192 epoch comparison.
95
+ * - Both arrays \u2192 compared with `array/equalsDeep` (leaf, no diff drill-down).
96
+ * - Special objects (Map, Set, RegExp, Promise, class instances\u2026) \u2192 reference equality.
97
+ * - Plain objects \u2192 key-by-key, recursing up to `options.depth` levels.
98
+ * - Mixed types (e.g. array vs object, Date vs object) \u2192 `false`.
99
+ *
100
+ * For a boolean wrapper see {@link equalsDeep} from this category.
101
+ * For a one-level boolean check see {@link equalsShallow} from this category.
28
102
  *
29
- * @param objA - First object to compare (can be object, undefined, or null)
30
- * @param objB - Second object to compare (can be object, undefined, or null)
31
- * @returns `true` if objects are identical, `false` if incompatible types, or a `DeepCompareResult` object detailing differences
103
+ * @param objA - First value (object, `null`, or `undefined`).
104
+ * @param objB - Second value (object, `null`, or `undefined`).
105
+ * @param options - See {@link DiffOptions}.
106
+ * @returns `true` when equal, otherwise a {@link DiffResult}, or `false` for incompatible types.
32
107
  * @since 2.0.0
33
108
  */
34
- declare function deepCompare(objA: object | undefined | null, objB: object | undefined | null): true | false | DeepCompareResult;
109
+ declare function diff(objA: object | undefined | null, objB: object | undefined | null, options?: DiffOptions): true | false | DiffResult;
35
110
 
36
111
  /**
37
112
  * This file is part of helpers4.
@@ -39,13 +114,48 @@ declare function deepCompare(objA: object | undefined | null, objB: object | und
39
114
  * SPDX-License-Identifier: LGPL-3.0-or-later
40
115
  */
41
116
  /**
42
- * Merges two or more objects deeply
43
- * @param target - The target object
44
- * @param sources - The source objects to merge
45
- * @returns The merged object
46
- * @since 1.9.0
117
+ * Recursive structural object equality.
118
+ *
119
+ * Boolean wrapper around {@link diff} \u2014 returns `true` when the two values
120
+ * are deeply equal according to the same rules. Use this when you only
121
+ * need a yes/no answer; use {@link diff} when you also need to know
122
+ * *what* differs.
123
+ *
124
+ * For a one-level boolean check use {@link equalsShallow}.
125
+ *
126
+ * @param objA - First value (object, `null`, or `undefined`).
127
+ * @param objB - Second value (object, `null`, or `undefined`).
128
+ * @returns `true` if both inputs are deeply equal, `false` otherwise.
129
+ * @since 2.0.0
130
+ */
131
+ declare function equalsDeep(objA: object | undefined | null, objB: object | undefined | null): boolean;
132
+
133
+ /**
134
+ * This file is part of helpers4.
135
+ * Copyright (C) 2025 baxyz
136
+ * SPDX-License-Identifier: LGPL-3.0-or-later
137
+ */
138
+ /**
139
+ * One-level (shallow) object equality.
140
+ *
141
+ * Two objects are equal when they share the exact same set of own
142
+ * enumerable string keys and each pair of values satisfies strict equality
143
+ * (`===`). No recursion: nested objects/arrays are compared by reference.
144
+ *
145
+ * Falls back to strict equality when either input is `null`, `undefined`
146
+ * or not an object \u2014 so primitives match if and only if they are `===`.
147
+ * Arrays are not supported; they always return `false` (unless identical
148
+ * references). Use `array/equalsShallow` instead.
149
+ *
150
+ * For recursive structural comparison use {@link equalsDeep}. For a diff
151
+ * structure use {@link diff}.
152
+ *
153
+ * @param objA - First value to compare
154
+ * @param objB - Second value to compare
155
+ * @returns `true` if values are shallowly equal, `false` otherwise.
156
+ * @since 2.0.0
47
157
  */
48
- declare function deepMerge<T extends Record<string, any>>(target: T, ...sources: Record<string, any>[]): T;
158
+ declare function equalsShallow(objA: unknown, objB: unknown): boolean;
49
159
 
50
160
  /**
51
161
  * This file is part of helpers4.
@@ -60,7 +170,7 @@ declare function deepMerge<T extends Record<string, any>>(target: T, ...sources:
60
170
  * @returns The value at the path or default value
61
171
  * @since 1.9.0
62
172
  */
63
- declare function get<T = any>(obj: any, path: string, defaultValue?: T): T | undefined;
173
+ declare function get<T = unknown>(obj: unknown, path: string, defaultValue?: T): T | undefined;
64
174
 
65
175
  /**
66
176
  * This file is part of helpers4.
@@ -68,15 +178,113 @@ declare function get<T = any>(obj: any, path: string, defaultValue?: T): T | und
68
178
  * SPDX-License-Identifier: LGPL-3.0-or-later
69
179
  */
70
180
  /**
71
- * Quick comparison of two objects using JSON.stringify.
72
- * This is a fast but simple comparison that may not work for all edge cases.
181
+ * Groups an array of items by a key derived from each item.
73
182
  *
74
- * @param objA - First object to compare
75
- * @param objB - Second object to compare
76
- * @returns `true` if objects are identical according to JSON.stringify, `false` otherwise
183
+ * A thin, typed wrapper around `Object.groupBy` (ES2024) that works on
184
+ * older targets and provides stricter return-type inference.
185
+ *
186
+ * @param items - The array to group
187
+ * @param keyFn - Function that returns the group key for each item
188
+ * @returns A record mapping each key to the array of items with that key
189
+ * @example
190
+ * groupBy([1, 2, 3, 4], n => n % 2 === 0 ? 'even' : 'odd')
191
+ * // => { odd: [1, 3], even: [2, 4] }
192
+ * @since next
193
+ */
194
+ declare function groupBy<T, K extends PropertyKey>(items: readonly T[], keyFn: (item: T) => K): Partial<Record<K, T[]>>;
195
+
196
+ /**
197
+ * This file is part of helpers4.
198
+ * Copyright (C) 2025 baxyz
199
+ * SPDX-License-Identifier: LGPL-3.0-or-later
200
+ */
201
+ /**
202
+ * Returns a new object with keys and values swapped.
203
+ * If multiple keys share the same value, the last one wins.
204
+ *
205
+ * @param obj - The object whose keys and values are to be swapped
206
+ * @returns A new object with values as keys and original keys as values
207
+ * @example
208
+ * invert({ a: 'x', b: 'y', c: 'z' })
209
+ * // => { x: 'a', y: 'b', z: 'c' }
210
+ *
211
+ * invert({ one: 1, two: 2 })
212
+ * // => { 1: 'one', 2: 'two' }
213
+ * @since next
214
+ */
215
+ declare function invert<K extends string, V extends PropertyKey>(obj: Record<K, V>): Record<V, K>;
216
+
217
+ /**
218
+ * This file is part of helpers4.
219
+ * Copyright (C) 2025 baxyz
220
+ * SPDX-License-Identifier: LGPL-3.0-or-later
221
+ */
222
+ /**
223
+ * Transforms the values and/or keys of a plain object in a single pass.
224
+ *
225
+ * Both callbacks are optional and default to identity (no transformation).
226
+ * When `mapValue` is omitted the original values are preserved;
227
+ * when `mapKey` is omitted the original keys are preserved.
228
+ *
229
+ * Note: if two different keys map to the same output key the last one wins
230
+ * (insertion order).
231
+ *
232
+ * @param obj - The source object
233
+ * @param mapValue - Callback called with `(value, key)` for each entry.
234
+ * Defaults to identity.
235
+ * @param mapKey - Callback called with `(key, value)` for each entry.
236
+ * Defaults to identity.
237
+ * @returns A new object with transformed keys and/or values
238
+ * @example
239
+ * map({ a: 1, b: 2 }, v => v * 10)
240
+ * // => { a: 10, b: 20 }
241
+ *
242
+ * map({ a: 1, b: 2 }, undefined, k => k.toUpperCase())
243
+ * // => { A: 1, B: 2 }
244
+ *
245
+ * map({ a: 1, b: 2 }, v => v * 10, k => k.toUpperCase())
246
+ * // => { A: 10, B: 20 }
247
+ * @since next
248
+ */
249
+ declare function map<TObj extends Record<string, unknown>, TVal = TObj[keyof TObj], TKey extends PropertyKey = keyof TObj>(obj: TObj, mapValue?: (value: TObj[keyof TObj], key: keyof TObj) => TVal, mapKey?: (key: keyof TObj, value: TObj[keyof TObj]) => TKey): Record<TKey, TVal>;
250
+
251
+ /**
252
+ * This file is part of helpers4.
253
+ * Copyright (C) 2025 baxyz
254
+ * SPDX-License-Identifier: LGPL-3.0-or-later
255
+ */
256
+ /**
257
+ * Creates a new object without the specified keys.
258
+ * @param obj - The source object
259
+ * @param keys - The keys to omit
260
+ * @returns A new object without the omitted keys
261
+ * @example
262
+ * omit({ a: 1, b: 2, c: 3 }, ['b'])
263
+ * // => { a: 1, c: 3 }
77
264
  * @since 2.0.0
78
265
  */
79
- declare function quickCompare(objA: unknown, objB: unknown): boolean;
266
+ declare function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K>;
267
+ declare function omit(obj: undefined, keys: readonly string[]): undefined;
268
+ declare function omit(obj: null, keys: readonly string[]): null;
269
+
270
+ /**
271
+ * This file is part of helpers4.
272
+ * Copyright (C) 2025 baxyz
273
+ * SPDX-License-Identifier: LGPL-3.0-or-later
274
+ */
275
+ /**
276
+ * Creates a new object with only the specified keys.
277
+ * @param obj - The source object
278
+ * @param keys - The keys to pick
279
+ * @returns A new object with only the picked keys
280
+ * @example
281
+ * pick({ a: 1, b: 2, c: 3 }, ['a', 'c'])
282
+ * // => { a: 1, c: 3 }
283
+ * @since 2.0.0
284
+ */
285
+ declare function pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K>;
286
+ declare function pick(obj: undefined, keys: readonly string[]): undefined;
287
+ declare function pick(obj: null, keys: readonly string[]): null;
80
288
 
81
289
  /**
82
290
  * This file is part of helpers4.
@@ -108,6 +316,29 @@ declare function removeUndefinedNull(obj: null): null;
108
316
  */
109
317
  declare function removeUndefinedNull(obj: undefined): undefined;
110
318
 
319
+ /**
320
+ * This file is part of helpers4.
321
+ * Copyright (C) 2025 baxyz
322
+ * SPDX-License-Identifier: LGPL-3.0-or-later
323
+ */
324
+ /**
325
+ * Parses a JSON string, returning `null` (or a fallback) on any parse failure.
326
+ *
327
+ * Unlike `JSON.parse`, this never throws. Invalid JSON strings and other
328
+ * parsing edge-cases resolve to `null` or the provided `fallback`.
329
+ *
330
+ * @param input - The JSON string to parse.
331
+ * @param fallback - Value returned on failure. Defaults to `null` when omitted.
332
+ * @returns The parsed value typed as `T`, or `fallback` on failure.
333
+ * @example
334
+ * safeJsonParse<{ a: number }>('{"a":1}') // => { a: 1 }
335
+ * safeJsonParse('invalid') // => null
336
+ * safeJsonParse('invalid', []) // => []
337
+ * @since next
338
+ */
339
+ declare function safeJsonParse<T>(input: string): T | null;
340
+ declare function safeJsonParse<T>(input: string, fallback: T): T;
341
+
111
342
  /**
112
343
  * This file is part of helpers4.
113
344
  * Copyright (C) 2025 baxyz
@@ -121,7 +352,7 @@ declare function removeUndefinedNull(obj: undefined): undefined;
121
352
  * @returns The modified object
122
353
  * @since 1.9.0
123
354
  */
124
- declare function set(obj: Record<string, any>, path: string, value: any): Record<string, any>;
355
+ declare function set(obj: Record<string, unknown>, path: string, value: unknown): Record<string, unknown>;
125
356
 
126
- export { deepClone, deepCompare, deepMerge, get, quickCompare, removeUndefinedNull, set };
127
- export type { DeepCompareResult };
357
+ export { compact, deepClone, deepMerge, diff, equalsDeep, equalsShallow, get, groupBy, invert, map, omit, pick, removeUndefinedNull, safeJsonParse, set };
358
+ export type { DiffOptions, DiffResult };