@helpers4/object 3.0.0-alpha.2 → 3.0.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 CHANGED
@@ -12,11 +12,13 @@ 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
+ - clone
15
16
  - cloneDeep
16
17
  - compact
17
18
  - diff
18
19
  - equalsDeep
19
20
  - equalsShallow
21
+ - flatten
20
22
  - get
21
23
  - groupBy
22
24
  - invert
@@ -25,10 +27,16 @@ A set of helpers for working with URLs.
25
27
  - map
26
28
  - mergeDeep
27
29
  - omit
30
+ - omitBy
31
+ - parsePropertyPath
28
32
  - pick
33
+ - pickBy
29
34
  - removeUndefinedNull
30
35
  - safeJsonParse
31
36
  - set
37
+ - unflatten
38
+ - unset
39
+ - update
32
40
  <!-- /AUTOMATIC-METHODS -->
33
41
 
34
42
  ## See
package/lib/index.d.ts CHANGED
@@ -1,3 +1,31 @@
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
+ * Creates a shallow copy of a value — one level deep, unlike {@link cloneDeep}.
8
+ *
9
+ * Unlike a plain `{ ...value }` spread, this correctly reconstructs `Date`,
10
+ * `Map`, `Set`, and arrays instead of producing an empty (or wrong-shaped)
11
+ * plain object for them. Primitives are returned as-is. Any other object
12
+ * (including class instances not listed above) has its own enumerable string
13
+ * keys shallow-copied into a plain object — the same fallback `cloneDeep`
14
+ * uses, so the two stay consistent for types neither one special-cases.
15
+ *
16
+ * @param value - The value to shallow-clone
17
+ * @returns A shallow copy of `value`
18
+ * @example
19
+ * clone({ a: { b: 1 } })
20
+ * // => { a: { b: 1 } } — new object, but `a` is the *same* nested reference
21
+ * @example
22
+ * clone(new Date('2024-01-01')) // => new Date with the same timestamp
23
+ * clone(new Map([['a', 1]])) // => new Map with the same entries
24
+ * clone([1, 2, 3]) // => new array, same elements
25
+ * @since 3.0.0
26
+ */
27
+ declare function clone<T>(value: T): T;
28
+
1
29
  /**
2
30
  * This file is part of helpers4.
3
31
  * Copyright (C) 2025 baxyz
@@ -162,6 +190,37 @@ declare function equalsDeep(objA: object | undefined | null, objB: object | unde
162
190
  */
163
191
  declare function equalsShallow(objA: unknown, objB: unknown): boolean;
164
192
 
193
+ /**
194
+ * This file is part of helpers4.
195
+ * Copyright (C) 2025 baxyz
196
+ * SPDX-License-Identifier: LGPL-3.0-or-later
197
+ */
198
+ /**
199
+ * Flattens a nested object into a single-level object whose keys are the
200
+ * dot-notation path to each leaf value. The inverse of {@link unflatten}.
201
+ *
202
+ * Only **plain objects** are recursed into — arrays, `Date`, `Map`, `RegExp`,
203
+ * class instances, and empty plain objects `{}` are kept as opaque leaf
204
+ * values. This keeps `flatten`/`unflatten` a clean, invertible pair: arrays
205
+ * can't be losslessly told apart from plain objects once reduced to dotted
206
+ * keys, so this implementation doesn't attempt it.
207
+ *
208
+ * Caveat shared by every dotted-path flattening scheme: a key that itself
209
+ * contains a literal `.` is indistinguishable from real nesting once
210
+ * flattened (`{ 'a.b': 1 }` and `{ a: { b: 1 } }` both produce `{ 'a.b': 1 }`).
211
+ *
212
+ * @param obj - The object to flatten
213
+ * @returns A single-level object with dot-notation keys
214
+ * @example
215
+ * flatten({ a: { b: { c: 1 }, d: 2 } })
216
+ * // => { 'a.b.c': 1, 'a.d': 2 }
217
+ * @example
218
+ * flatten({ a: [1, 2], b: new Date(0) })
219
+ * // => { a: [1, 2], b: Date } (arrays and special objects stay as leaves)
220
+ * @since 3.0.0
221
+ */
222
+ declare function flatten(obj: Record<string, unknown>): Record<string, unknown>;
223
+
165
224
  /**
166
225
  * This file is part of helpers4.
167
226
  * Copyright (C) 2025 baxyz
@@ -175,6 +234,101 @@ declare const UNSAFE_KEY_LIST: readonly ["__proto__", "constructor", "prototype"
175
234
  /** @ignore */
176
235
  type UnsafeKey = (typeof UNSAFE_KEY_LIST)[number];
177
236
 
237
+ /**
238
+ * This file is part of helpers4.
239
+ * Copyright (C) 2025 baxyz
240
+ * SPDX-License-Identifier: LGPL-3.0-or-later
241
+ */
242
+ /**
243
+ * Converts a union type to an intersection type: `A | B | C` → `A & B & C`.
244
+ *
245
+ * Uses conditional-type distribution and the contravariant position of a
246
+ * function parameter to collapse the union into an intersection.
247
+ *
248
+ * @example
249
+ * type Union = { a: number } | { b: string } | { c: boolean };
250
+ * type Intersection = UnionToIntersection<Union>;
251
+ * // { a: number } & { b: string } & { c: boolean }
252
+ *
253
+ * type Keys = UnionToIntersection<'a' | 'b'>;
254
+ * // 'a' & 'b' (resolves to never for disjoint literals)
255
+ * @since 3.0.0
256
+ */
257
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
258
+
259
+ /**
260
+ * This file is part of helpers4.
261
+ * Copyright (C) 2025 baxyz
262
+ * SPDX-License-Identifier: LGPL-3.0-or-later
263
+ */
264
+ /**
265
+ * Returns `never` for `null`/`undefined`, otherwise `keyof T`.
266
+ *
267
+ * Used instead of inlining `keyof NonNullable<T>` at each `DeepGet` recursion
268
+ * step — TypeScript doesn't evaluate that expression eagerly inside a
269
+ * recursive generic, so `keyof` ends up applied to an unresolved conditional
270
+ * type instead of a concrete one. That collapses the whole recursive chain to
271
+ * `never` (rather than `unknown`) the moment a path travels through a
272
+ * property whose value is `null`, even though `null` itself is never in
273
+ * `Path`. Checking the null-ness first, in its own conditional, forces eager
274
+ * resolution and keeps that case at `unknown` as intended.
275
+ * @ignore
276
+ */
277
+ type KeysOf<T> = T extends null | undefined ? never : keyof T;
278
+ /**
279
+ * Resolves the value type at a given `Path` within `T`.
280
+ *
281
+ * Returns `unknown` when any key in `Path` is not present in the corresponding
282
+ * level of `T`. An empty path resolves to `T` itself. A path segment that goes
283
+ * through an optional property keeps the result nullable (`V | undefined`)
284
+ * instead of degrading to `unknown`.
285
+ *
286
+ * @example
287
+ * type Obj = { a: { b: { c: number } } };
288
+ *
289
+ * DeepGet<Obj, ['a', 'b', 'c']> // => number
290
+ * DeepGet<Obj, ['a', 'b']> // => { c: number }
291
+ * DeepGet<Obj, ['a', 'x']> // => unknown
292
+ * DeepGet<Obj, []> // => Obj
293
+ *
294
+ * type WithOptional = { a?: { b: number } };
295
+ * DeepGet<WithOptional, ['a', 'b']> // => number | undefined
296
+ * @since 3.0.0
297
+ */
298
+ type DeepGet<T, Path extends readonly PropertyKey[]> = Path extends readonly [] ? T : Path extends readonly [infer K, ...infer Rest extends readonly PropertyKey[]] ? K extends KeysOf<T> ? DeepGet<NonNullable<T>[K & keyof NonNullable<T>], Rest> | (undefined extends T ? undefined : never) : unknown : unknown;
299
+
300
+ /**
301
+ * This file is part of helpers4.
302
+ * Copyright (C) 2025 baxyz
303
+ * SPDX-License-Identifier: LGPL-3.0-or-later
304
+ */
305
+ /**
306
+ * Builds a brand-new nested object type from the remaining path segments and a leaf value type.
307
+ * Used by `DeepSet` once a path segment no longer matches an existing key on T.
308
+ * @ignore
309
+ */
310
+ type BuildPath<Path extends readonly PropertyKey[], V> = Path extends readonly [infer K extends PropertyKey, ...infer Rest extends readonly PropertyKey[]] ? Record<K, BuildPath<Rest, V>> : V;
311
+ /**
312
+ * Produces the type of `T` after replacing the value at `Path` with `V`.
313
+ *
314
+ * When a key in `Path` is absent from the corresponding level of `T`, that level
315
+ * (and everything below it) is added as a new field instead of resolving to
316
+ * `never` — mirroring how `set()` creates intermediate objects at runtime.
317
+ *
318
+ * @example
319
+ * type Obj = { a: { b: number; c: string } };
320
+ *
321
+ * DeepSet<Obj, ['a', 'b'], string>
322
+ * // => { a: { b: string; c: string } }
323
+ *
324
+ * DeepSet<Obj, ['a', 'x'], boolean>
325
+ * // => { a: { b: number; c: string } & { x: boolean } }
326
+ * @since 3.0.0
327
+ */
328
+ type DeepSet<T, Path extends readonly PropertyKey[], V> = Path extends readonly [] ? V : Path extends readonly [infer K extends PropertyKey, ...infer Rest extends readonly PropertyKey[]] ? T extends object ? K extends keyof T ? {
329
+ [P in keyof T]: P extends K ? DeepSet<T[K], Rest, V> : T[P];
330
+ } : T & Record<K, BuildPath<Rest, V>> : BuildPath<Path, V> : never;
331
+
178
332
  /**
179
333
  * This file is part of helpers4.
180
334
  * Copyright (C) 2025 baxyz
@@ -222,12 +376,6 @@ type ParsePath<P extends string | readonly PropertyKey[]> = P extends string ? P
222
376
  * @ignore
223
377
  */
224
378
  type ContainsUnsafeStringKey<Keys extends readonly PropertyKey[]> = Keys extends readonly [infer K, ...infer Rest extends readonly PropertyKey[]] ? K extends UnsafeKey ? true : ContainsUnsafeStringKey<Rest> : false;
225
- /**
226
- * Converts a union to an intersection: `A | B | C` → `A & B & C`.
227
- * Used to derive the return type of `mergeDeep` from a tuple of source types.
228
- * @ignore
229
- */
230
- type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
231
379
  /**
232
380
  * Return type of `mergeDeep`: intersection of all source types.
233
381
  *
@@ -237,57 +385,6 @@ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) exten
237
385
  * MergeResult<[{ a: { b: number } }, { a: { c: string } }]> // { a: { b: number } & { c: string } }
238
386
  */
239
387
  type MergeResult<T extends object[]> = UnionToIntersection<T[number]>;
240
- /**
241
- * Returns `never` for `null`/`undefined`, otherwise `keyof T`.
242
- *
243
- * Used instead of inlining `keyof NonNullable<T>` at each `DeepGet` recursion
244
- * step — TypeScript doesn't evaluate that expression eagerly inside a
245
- * recursive generic, so `keyof` ends up applied to an unresolved conditional
246
- * type instead of a concrete one. That collapses the whole recursive chain to
247
- * `never` (rather than `unknown`) the moment a path travels through a
248
- * property whose value is `null`, even though `null` itself is never in
249
- * `Path`. Checking the null-ness first, in its own conditional, forces eager
250
- * resolution and keeps that case at `unknown` as intended.
251
- * @ignore
252
- */
253
- type KeysOf<T> = T extends null | undefined ? never : keyof T;
254
- /**
255
- * Resolves the value type at a given path within T.
256
- * Returns `unknown` when the path doesn't match the shape of T. A path segment
257
- * that goes through an optional property keeps the result nullable
258
- * (`V | undefined`) instead of degrading to `unknown`.
259
- *
260
- * @ignore
261
- * @example
262
- * DeepGet<{ a: { b: number } }, ['a', 'b']> // => number
263
- * DeepGet<{ a: { b: number } }, ['a', 'x']> // => unknown
264
- * DeepGet<{ a: number }, []> // => { a: number }
265
- * DeepGet<{ a?: { b: number } }, ['a', 'b']> // => number | undefined
266
- * DeepGet<{ a: { b: null } }, ['a', 'b', 'c']> // => unknown (not never)
267
- */
268
- type DeepGet<T, Path extends readonly PropertyKey[]> = Path extends readonly [] ? T : Path extends readonly [infer K, ...infer Rest extends readonly PropertyKey[]] ? K extends KeysOf<T> ? DeepGet<NonNullable<T>[K & keyof NonNullable<T>], Rest> | (undefined extends T ? undefined : never) : unknown : unknown;
269
- /**
270
- * Builds a brand-new nested object type from the remaining path segments and a leaf value type.
271
- * Used by `DeepSet` once a path segment no longer matches an existing key on T.
272
- * @ignore
273
- */
274
- type BuildPath<Path extends readonly PropertyKey[], V> = Path extends readonly [infer K extends PropertyKey, ...infer Rest extends readonly PropertyKey[]] ? Record<K, BuildPath<Rest, V>> : V;
275
- /**
276
- * Produces the type of T after setting the value at Path to V.
277
- * When a key in Path is not present at the corresponding level of T, that level (and
278
- * everything below it) is added as a new field instead of resolving to `never` — matching
279
- * the runtime behavior of `set`, which creates intermediate objects as needed.
280
- *
281
- * @ignore
282
- * @example
283
- * DeepSet<{ a: { b: number } }, ['a', 'b'], string>
284
- * // => { a: { b: string } }
285
- * DeepSet<{ a: { b: number } }, ['a', 'c'], string>
286
- * // => { a: { b: number } & { c: string } }
287
- */
288
- type DeepSet<T, Path extends readonly PropertyKey[], V> = Path extends readonly [] ? V : Path extends readonly [infer K extends PropertyKey, ...infer Rest extends readonly PropertyKey[]] ? K extends keyof T ? {
289
- [P in keyof T]: P extends K ? DeepSet<T[K], Rest, V> : T[P];
290
- } : T & Record<K, BuildPath<Rest, V>> : never;
291
388
 
292
389
  /**
293
390
  * This file is part of helpers4.
@@ -549,6 +646,60 @@ declare function omit<T extends Record<string, unknown>, K extends keyof T>(obj:
549
646
  declare function omit(obj: undefined, keys: readonly string[]): undefined;
550
647
  declare function omit(obj: null, keys: readonly string[]): null;
551
648
 
649
+ /**
650
+ * This file is part of helpers4.
651
+ * Copyright (C) 2025 baxyz
652
+ * SPDX-License-Identifier: LGPL-3.0-or-later
653
+ */
654
+ /**
655
+ * Creates a new object without the own enumerable entries for which
656
+ * `predicate` returns `true`.
657
+ *
658
+ * Complements {@link omit} for when the keys to remove aren't known ahead of
659
+ * time — `omit` takes an explicit key list, `omitBy` takes a predicate.
660
+ *
661
+ * @param obj - The source object. `null`/`undefined` pass through unchanged.
662
+ * @param predicate - Called with `(value, key)` for each own enumerable entry
663
+ * @returns A new object without the matching entries
664
+ * @example
665
+ * omitBy({ a: 1, b: undefined, c: 2 }, (value) => value === undefined)
666
+ * // => { a: 1, c: 2 }
667
+ * @since 3.0.0
668
+ */
669
+ declare function omitBy<T extends Record<string, unknown>>(obj: T | undefined | null, predicate: (value: T[keyof T], key: keyof T) => boolean): Partial<T> | undefined | null;
670
+
671
+ /**
672
+ * This file is part of helpers4.
673
+ * Copyright (C) 2025 baxyz
674
+ * SPDX-License-Identifier: LGPL-3.0-or-later
675
+ */
676
+ /**
677
+ * Parses a dot/bracket-notation property path into an array of string/number
678
+ * key segments — the same notation accepted by {@link get} and {@link set}.
679
+ *
680
+ * - Dot separators (`.`) split segments; each segment becomes a string key.
681
+ * - Bracket indices (`[n]`) become number keys.
682
+ * - A leading `.` is treated as "current level" and stripped before parsing,
683
+ * so `.[0]` ≡ `[0]` and `.a.b` ≡ `a.b`.
684
+ * - Empty string (or a bare `.`) returns `['']` (addresses the `''` key on the root object).
685
+ * - Consecutive dots (`a..b`) produce an empty-string segment: `['a', '', 'b']`.
686
+ *
687
+ * Results are cached (up to 500 distinct path strings, oldest evicted first)
688
+ * since real-world callers tend to reuse a small, fixed set of literal paths.
689
+ *
690
+ * @param path - The dot/bracket-notation path string to parse
691
+ * @returns The parsed key segments
692
+ * @throws {RangeError} When non-bracket text trails the last `]` within a
693
+ * dot-segment (e.g. `'a[0]b'` is ambiguous — use `'a[0].b'` instead)
694
+ * @example
695
+ * parsePropertyPath('a.b.c') // => ['a', 'b', 'c']
696
+ * parsePropertyPath('layers[1].x') // => ['layers', 1, 'x']
697
+ * parsePropertyPath('.[0]') // => [0] (leading dot stripped)
698
+ * parsePropertyPath('a..b') // => ['a', '', 'b'] (empty segment preserved)
699
+ * @since 3.0.0
700
+ */
701
+ declare function parsePropertyPath(path: string): readonly (string | number)[];
702
+
552
703
  /**
553
704
  * This file is part of helpers4.
554
705
  * Copyright (C) 2025 baxyz
@@ -570,6 +721,28 @@ declare function pick<T extends Record<string, unknown>, K extends keyof T>(obj:
570
721
  declare function pick(obj: undefined, keys: readonly string[]): undefined;
571
722
  declare function pick(obj: null, keys: readonly string[]): null;
572
723
 
724
+ /**
725
+ * This file is part of helpers4.
726
+ * Copyright (C) 2025 baxyz
727
+ * SPDX-License-Identifier: LGPL-3.0-or-later
728
+ */
729
+ /**
730
+ * Creates a new object with only the own enumerable entries for which
731
+ * `predicate` returns `true`.
732
+ *
733
+ * Complements {@link pick} for when the keys to keep aren't known ahead of
734
+ * time — `pick` takes an explicit key list, `pickBy` takes a predicate.
735
+ *
736
+ * @param obj - The source object. `null`/`undefined` pass through unchanged.
737
+ * @param predicate - Called with `(value, key)` for each own enumerable entry
738
+ * @returns A new object with only the matching entries
739
+ * @example
740
+ * pickBy({ a: 1, b: 0, c: 2 }, (value) => value > 0)
741
+ * // => { a: 1, c: 2 }
742
+ * @since 3.0.0
743
+ */
744
+ declare function pickBy<T extends Record<string, unknown>>(obj: T | undefined | null, predicate: (value: T[keyof T], key: keyof T) => boolean): Partial<T> | undefined | null;
745
+
573
746
  /**
574
747
  * This file is part of helpers4.
575
748
  * Copyright (C) 2025 baxyz
@@ -671,5 +844,88 @@ declare function safeJsonParse<T>(input: string, fallback: T): T;
671
844
  */
672
845
  declare function set<T extends object, const P extends string | readonly PropertyKey[], V extends DeepGet<T, ParsePath<P>>>(obj: T, path: P, value: V): string extends P ? T : readonly PropertyKey[] extends P ? T : ContainsUnsafeStringKey<ParsePath<P>> extends true ? T : DeepSet<T, ParsePath<P>, V>;
673
846
 
674
- export { cloneDeep, compact, diff, equalsDeep, equalsShallow, get, groupBy, invert, isEmpty, isNonEmpty, map, mergeDeep, omit, pick, removeUndefinedNull, safeJsonParse, set };
847
+ /**
848
+ * This file is part of helpers4.
849
+ * Copyright (C) 2025 baxyz
850
+ * SPDX-License-Identifier: LGPL-3.0-or-later
851
+ */
852
+ /**
853
+ * Rebuilds a nested object from a single-level object whose keys are
854
+ * dot-notation paths. The inverse of {@link flatten}.
855
+ *
856
+ * Uses {@link set} internally, so intermediate nodes are always created as
857
+ * plain objects (never arrays — see {@link flatten}'s doc for why), and any
858
+ * key segment equal to `__proto__`, `constructor`, or `prototype` is silently
859
+ * rejected (same prototype-pollution guard as `set`).
860
+ *
861
+ * @param obj - A single-level object with dot-notation keys
862
+ * @returns The rebuilt nested object
863
+ * @example
864
+ * unflatten({ 'a.b.c': 1, 'a.d': 2 })
865
+ * // => { a: { b: { c: 1 }, d: 2 } }
866
+ * @since 3.0.0
867
+ */
868
+ declare function unflatten(obj: Record<string, unknown>): Record<string, unknown>;
869
+
870
+ /**
871
+ * This file is part of helpers4.
872
+ * Copyright (C) 2025 baxyz
873
+ * SPDX-License-Identifier: LGPL-3.0-or-later
874
+ */
875
+ /**
876
+ * Removes the value at a dot/bracket-notation path or explicit key array,
877
+ * mutating the object in place. Uses the same path syntax as {@link get}/{@link set}.
878
+ *
879
+ * A missing intermediate segment is a no-op (nothing to remove), not an error.
880
+ * As with `set`, any path containing a string segment equal to `__proto__`,
881
+ * `constructor`, or `prototype` is rejected and the object is returned unchanged.
882
+ *
883
+ * The removed key stops appearing in `Object.keys`/`for...in` — unlike setting
884
+ * it to `undefined`, which would keep the key present.
885
+ *
886
+ * @param obj - The object to mutate
887
+ * @param path - Dot/bracket-notation string, or explicit `PropertyKey[]`
888
+ * @returns The same object reference, with the key removed if it existed
889
+ * @example
890
+ * unset({ a: { b: 1, c: 2 } }, 'a.b')
891
+ * // => { a: { c: 2 } }
892
+ * @example
893
+ * unset({ a: 1 }, 'x.y') // path doesn't exist — no-op
894
+ * // => { a: 1 }
895
+ * @since 3.0.0
896
+ */
897
+ declare function unset<T extends object>(obj: T, path: string | readonly PropertyKey[]): T;
898
+
899
+ /**
900
+ * This file is part of helpers4.
901
+ * Copyright (C) 2025 baxyz
902
+ * SPDX-License-Identifier: LGPL-3.0-or-later
903
+ */
904
+
905
+ /**
906
+ * Updates the value at a path by applying a function to its current value,
907
+ * creating intermediate objects as needed. Equivalent to
908
+ * `set(obj, path, updater(get(obj, path)))` in a single call.
909
+ *
910
+ * Uses the same path syntax and type-inference rules as {@link get} and
911
+ * {@link set} — see those for the full behavior (string vs. `PropertyKey[]`
912
+ * paths, prototype-pollution guarding, etc.).
913
+ *
914
+ * @param obj - The object to mutate
915
+ * @param path - Dot/bracket-notation string literal or explicit `PropertyKey[]`
916
+ * @param updater - Called with the current value (`undefined` if the path is
917
+ * absent); its return value is written back at the path
918
+ * @returns The mutated object (same reference, narrowed type)
919
+ * @example
920
+ * update({ count: 1 }, 'count', (n) => (n ?? 0) + 1)
921
+ * // => { count: 2 }
922
+ * @example
923
+ * // Missing intermediate objects are created, just like set()
924
+ * update({}, 'stats.hits', (n: number | undefined) => (n ?? 0) + 1)
925
+ * // => { stats: { hits: 1 } }
926
+ * @since 3.0.0
927
+ */
928
+ declare function update<T extends object, const P extends string | readonly PropertyKey[], V extends DeepGet<T, ParsePath<P>>>(obj: T, path: P, updater: (current: DeepGet<T, ParsePath<P>> | undefined) => V): string extends P ? T : readonly PropertyKey[] extends P ? T : ContainsUnsafeStringKey<ParsePath<P>> extends true ? T : DeepSet<T, ParsePath<P>, V>;
929
+
930
+ export { clone, cloneDeep, compact, diff, equalsDeep, equalsShallow, flatten, get, groupBy, invert, isEmpty, isNonEmpty, map, mergeDeep, omit, omitBy, parsePropertyPath, pick, pickBy, removeUndefinedNull, safeJsonParse, set, unflatten, unset, update };
675
931
  export type { DiffOptions, DiffResult };