@1nkvi/utils 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +23 -193
  2. package/build/artifacts/src/guard/index.d.ts +1 -0
  3. package/build/artifacts/src/guard/index.js +1 -0
  4. package/build/artifacts/src/index.d.ts +2 -0
  5. package/build/artifacts/src/index.js +2 -0
  6. package/build/artifacts/src/merge/index.d.ts +0 -1
  7. package/build/artifacts/src/merge/index.js +0 -1
  8. package/build/artifacts/src/merge/isInvalidPrimitive.js +1 -1
  9. package/build/artifacts/src/merge/merge.d.ts +1 -1
  10. package/build/artifacts/src/merge/merge.js +1 -1
  11. package/build/artifacts/src/merge/mergeArrays.js +1 -1
  12. package/build/artifacts/src/object/index.d.ts +1 -0
  13. package/build/artifacts/src/object/index.js +1 -0
  14. package/build/artifacts/src/object/replace.d.ts +7 -0
  15. package/build/artifacts/src/object/replace.js +27 -0
  16. package/build/artifacts/src/types/DotPaths.d.ts +14 -0
  17. package/build/artifacts/src/types/DotPaths.js +1 -0
  18. package/build/artifacts/src/types/DotPathsWithArrayIndex.d.ts +21 -0
  19. package/build/artifacts/src/types/DotPathsWithArrayIndex.js +1 -0
  20. package/build/artifacts/src/types/FlatObject.d.ts +59 -0
  21. package/build/artifacts/src/types/FlatObject.js +1 -0
  22. package/build/artifacts/src/types/IsPlainObject.d.ts +15 -0
  23. package/build/artifacts/src/types/IsPlainObject.js +1 -0
  24. package/build/artifacts/src/types/LeafDotPaths.d.ts +20 -0
  25. package/build/artifacts/src/types/LeafDotPaths.js +1 -0
  26. package/build/artifacts/src/types/index.d.ts +6 -0
  27. package/build/artifacts/src/types/index.js +6 -0
  28. package/package.json +1 -1
  29. /package/build/artifacts/src/{merge → guard}/utils.d.ts +0 -0
  30. /package/build/artifacts/src/{merge → guard}/utils.js +0 -0
  31. /package/build/artifacts/src/{merge → types}/DeepPartial.d.ts +0 -0
  32. /package/build/artifacts/src/{merge → types}/DeepPartial.js +0 -0
package/README.md CHANGED
@@ -1,206 +1,36 @@
1
1
  # @1nkvi/utils
2
2
 
3
- Helper functions for **deeply merging** partial objects and arrays, plus a few small array/value utilities. Give it a
4
- list of partial objects and it composes them into one — overriding primitives, concatenating and de-duplicating arrays,
5
- and merging nested objects recursively — while filtering out "empty" values like `null`, `undefined` and `""`.
6
-
7
- ## Quick start
8
-
9
- ```ts
10
- import { merge } from "@1nkvi/utils"
11
-
12
- merge([{ id: 1 }, { name: "Ada" }, { name: "Ada Lovelace" }])
13
- // → { id: 1, name: "Ada Lovelace" }
14
- ```
15
-
16
- Every export is available from the package root:
17
-
18
- ```ts
19
- import {
20
- merge,
21
- mergeArrays,
22
- filterValidPrimitiveArrayValues,
23
- tuplify,
24
- isPlainObject,
25
- isEmptyObject,
26
- isEmptyArray,
27
- isInvalidNumber,
28
- } from "@1nkvi/utils"
29
- ```
30
-
31
- ---
32
-
33
- ## `merge(values, options?)`
34
-
35
- Deeply merges an array of partial objects (left to right) into a single object.
36
-
37
- ```ts
38
- merge<TData>(values: Array<Partial<TData>>, options?: MergeOptions): Partial<TData>
3
+ ```shell
4
+ pnpm i @1nkvi/utils
39
5
  ```
40
6
 
41
- The result is a _deep partial_ of `TData` it contains every key seen across the inputs that passed validation, but no
42
- field is guaranteed to be present.
7
+ A small collection of TypeScript helper functions and utility types. Its centerpiece is **deeply merging** partial
8
+ objects and arrays composing a list of partials into one while overriding primitives, concatenating and de-duplicating
9
+ arrays, and merging nested objects recursively, all while filtering out "empty" values like `null`, `undefined` and
10
+ `""`. Alongside it are a handful of array, map, randomness, and type-guard utilities, plus reusable object/path utility
11
+ types.
43
12
 
44
- ### How it merges
13
+ ## Changelog
45
14
 
46
- - **Primitives** — the last _valid_ value wins. Invalid values (see [Invalid primitives](#invalid-primitives)) are
47
- skipped, so a later `""` or `null` won't clobber an earlier real value.
48
- - **Arrays** — concatenated, then primitive values are de-duplicated. (Objects/arrays nested inside an array are kept
49
- as-is.)
50
- - **Objects** — merged recursively, to any depth.
51
- - **Mixed primitive vs. array** for the same key — the array wins by default. With `enableSingleValueArrays`, the single
52
- value is wrapped into the array instead so nothing is lost.
53
- - Inputs are **never mutated**; a new object is returned.
15
+ [Changelog link](./CHANGELOG.md)
54
16
 
55
- ### Examples
56
-
57
- ```ts
58
- // Compose keys from several partials
59
- merge([{ int: 1 }, { float: 2.3 }, { text: "Hello" }])
60
- // → { int: 1, float: 2.3, text: "Hello" }
61
-
62
- // Later valid primitives override earlier ones; "" is ignored
63
- merge([{ int: 1, text: "Hello" }, { int: 2, text: "" }, { int: 3 }])
64
- // → { int: 3, text: "Hello" }
65
-
66
- // Arrays concatenate and de-duplicate
67
- merge([{ nums: [1, 2, 3] }, { nums: [4] }])
68
- // → { nums: [1, 2, 3, 4] }
69
-
70
- // Primitive vs. array on the same key — the array wins
71
- merge([{ text: "first" }, { text: ["second", "third"] }])
72
- // → { text: ["second", "third"] }
73
-
74
- // ...unless you opt into folding the single value in
75
- merge([{ text: "first" }, { text: ["second", "third"] }], { enableSingleValueArrays: true })
76
- // → { text: ["first", "second", "third"] }
77
-
78
- // Nested objects and arrays of objects merge recursively
79
- merge([{ node: [{ text: "A", children: [{ text: "A.1" }] }] }, { node: [{ int: 20 }] }])
80
- // → { node: [{ text: "A", children: [{ text: "A.1" }] }, { int: 20 }] }
81
- ```
82
-
83
- ### `MergeOptions`
84
-
85
- | Option | Default | Effect |
86
- | -------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
87
- | `enableSingleValueArrays` | `false` | When a key mixes a single value and an array, wrap the single value into the array (instead of letting the array replace it). |
88
- | `disableDistinctPrimitiveFilter` | `false` | Keep duplicate primitives in merged arrays instead of de-duplicating. |
89
- | `nullIsValid` | `false` | Treat `null` as a valid value (don't filter it out). |
90
- | `undefinedIsValid` | `false` | Treat `undefined` as a valid value. |
91
- | `emptyStringIsValid` | `false` | Treat `""` as a valid value. |
92
- | `validators` | `[]` | Extra predicates `(value) => boolean`; returning `true` marks a value **invalid** and filters it out. |
93
-
94
- ---
95
-
96
- ## `mergeArrays(arrays, options?)`
97
-
98
- Flattens several arrays into one. By default, primitive values are de-duplicated and invalid primitives are dropped.
99
-
100
- ```ts
101
- mergeArrays<TData>(arrays: TData[][], options?: MergeArraysOptions): TData[]
102
- ```
103
-
104
- ```ts
105
- mergeArrays([["first"], ["second"], ["third", "fourth"]])
106
- // → ["first", "second", "third", "fourth"]
107
-
108
- // Duplicates removed
109
- mergeArrays([["first"], ["first", "second"]])
110
- // → ["first", "second"]
111
-
112
- // Invalid primitives ("" here) are filtered out
113
- mergeArrays([["first"], [""]])
114
- // → ["first"]
115
-
116
- // Keep everything as-is
117
- mergeArrays([["first"], ["first", ""]], { disableDistinctPrimitiveFilter: true })
118
- // → ["first", "first", ""]
119
- ```
120
-
121
- ### `MergeArraysOptions`
122
-
123
- | Option | Default | Effect |
124
- | -------------------------------- | ------- | -------------------------------------------------------------------- |
125
- | `disableDistinctPrimitiveFilter` | `false` | Keep duplicates and invalid primitives instead of filtering. |
126
- | `nullIsValid` | `false` | Treat `null` as valid. |
127
- | `undefinedIsValid` | `false` | Treat `undefined` as valid. |
128
- | `emptyStringIsValid` | `false` | Treat `""` as valid. |
129
- | `validators` | `[]` | Extra `(value) => boolean` predicates; `true` marks a value invalid. |
130
-
131
- ---
132
-
133
- ## `filterValidPrimitiveArrayValues(flatArray, options?)`
134
-
135
- Takes a single flat array, removes invalid primitives, and de-duplicates the rest.
136
-
137
- ```ts
138
- filterValidPrimitiveArrayValues<TData>(flatArray: TData[], options?): TData[]
139
- ```
140
-
141
- ```ts
142
- filterValidPrimitiveArrayValues(["first", "", null, "second", "second"])
143
- // → ["first", "second"]
144
- ```
145
-
146
- Accepts the same validity overrides as above (`nullIsValid`, `undefinedIsValid`, `emptyStringIsValid`).
147
-
148
- ---
149
-
150
- ## Invalid primitives
151
-
152
- The merge/filter functions skip values considered "empty" or "meaningless". By default these are:
153
-
154
- - `null`
155
- - `undefined`
156
- - empty string `""`
157
- - `NaN`
158
- - `Infinity` and `-Infinity`
159
- - empty array `[]`
160
- - empty object `{}`
161
-
162
- Note that **`0` and `false` are valid** — they are kept. You can relax the defaults per call with `nullIsValid` /
163
- `undefinedIsValid` / `emptyStringIsValid`, or add your own rules via `validators`:
17
+ ## Quick start
164
18
 
165
19
  ```ts
166
- // Drop any string that starts with a hash
167
- merge([{ tag: "release" }, { tag: "#draft" }], {
168
- validators: [(v) => typeof v === "string" && v.startsWith("#")],
169
- })
170
- // → { tag: "release" }
171
- ```
172
-
173
- ---
174
-
175
- ## `tuplify(value)`
176
-
177
- Wraps a single value into a one-element array, and leaves an existing array untouched. Handy for normalizing a `T | T[]`
178
- value into `T[]`.
20
+ import { merge } from "@1nkvi/utils"
179
21
 
180
- ```ts
181
- tuplify("a") // → ["a"]
182
- tuplify(["a", "b"]) // → ["a", "b"]
183
- tuplify([]) // → []
22
+ merge([{ id: 1 }, { name: "Ada" }, { name: "Ada Lovelace" }])
23
+ // → { id: 1, name: "Ada Lovelace" }
184
24
  ```
185
25
 
186
- ---
187
-
188
- ## Small value helpers
26
+ ## Modules
189
27
 
190
- Type-guards and number checks used internally, exposed for convenience:
191
-
192
- | Function | Returns `true` when… |
193
- | -------------------- | --------------------------------------------------------- |
194
- | `isPlainObject(v)` | `v` is a non-null object that isn't an array |
195
- | `isEmptyObject(v)` | `v` is a plain object with no own keys (`{}`) |
196
- | `isEmptyArray(v)` | `v` is an array of length `0` (`[]`) |
197
- | `isInvalidNumber(v)` | `v` is a number that is `NaN` or not finite (`±Infinity`) |
198
-
199
- ```ts
200
- isPlainObject({ a: 1 }) // → true
201
- isPlainObject([]) // → false
202
- isEmptyObject({}) // → true
203
- isEmptyArray([]) // → true
204
- isInvalidNumber(NaN) // → true
205
- isInvalidNumber(42) // → false
206
- ```
28
+ | Module | What it does |
29
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
+ | [array](./docs/array.md) | Create and normalize arrays: `tuplify` a value into an array, or build index/range arrays with `createArray` and `createRangeArray`. |
31
+ | [guard](./docs/guard.md) | Type guards and runtime checks: `isPlainObject`, `isEmptyObject`, `isEmptyArray`, `isInvalidNumber`, plus `triggerExhaustiveSwitch` for exhaustiveness. |
32
+ | [map](./docs/map.md) | `upsert` a `Map` entry — insert a value, or combine it with the existing one via a callback. |
33
+ | [merge](./docs/merge.md) | Deeply `merge` partial objects, `mergeArrays` with de-duplication, and `filterValidPrimitiveArrayValues`, all skipping "empty" values. |
34
+ | [object](./docs/object.md) | `replace` a single deeply nested value by dot-notation path — immutably and type-safely, without touching its siblings. |
35
+ | [random](./docs/random.md) | Random integers: `random` within inclusive/exclusive bounds, and `randomMarginalChange` to nudge a value by fixed and percentage margins. |
36
+ | [types](./docs/types.md) | Utility types for nested objects: `DeepPartial`, `DotPaths`, `LeafDotPaths`, `DotPathsWithArrayIndex`, `FlatObject`, `IsPlainObject`. |
@@ -1 +1,2 @@
1
1
  export * from "./triggerExhaustiveSwitch";
2
+ export * from "./utils";
@@ -1 +1,2 @@
1
1
  export * from "./triggerExhaustiveSwitch";
2
+ export * from "./utils";
@@ -2,4 +2,6 @@ export * from "./array";
2
2
  export * from "./merge";
3
3
  export * from "./guard";
4
4
  export * from "./map";
5
+ export * from "./object";
5
6
  export * from "./random";
7
+ export * from "./types";
@@ -2,4 +2,6 @@ export * from "./array";
2
2
  export * from "./merge";
3
3
  export * from "./guard";
4
4
  export * from "./map";
5
+ export * from "./object";
5
6
  export * from "./random";
7
+ export * from "./types";
@@ -1,4 +1,3 @@
1
1
  export * from "./merge";
2
2
  export * from "./mergeArrays";
3
- export * from "./utils";
4
3
  export * from "./filterValidPrimitiveArrayValues";
@@ -1,4 +1,3 @@
1
1
  export * from "./merge";
2
2
  export * from "./mergeArrays";
3
- export * from "./utils";
4
3
  export * from "./filterValidPrimitiveArrayValues";
@@ -1,4 +1,4 @@
1
- import { isEmptyArray, isEmptyObject, isInvalidNumber } from "../merge/utils";
1
+ import { isEmptyArray, isEmptyObject, isInvalidNumber } from "../guard/utils";
2
2
  export function isInvalidPrimitive(value, options) {
3
3
  if (options?.validators) {
4
4
  const customValidatorResult = options.validators?.some((validator) => validator(value));
@@ -1,5 +1,5 @@
1
1
  import { type MergeArraysOptions } from "../merge/mergeArrays";
2
- import type { DeepPartial } from "../merge/DeepPartial";
2
+ import type { DeepPartial } from "../types/DeepPartial";
3
3
  export type MergeOptions<TData> = Omit<MergeArraysOptions<TData>, "validators"> & {
4
4
  /**
5
5
  * If `true` - merging `TValue | TValue[]` results in `TValue[]`
@@ -1,5 +1,5 @@
1
1
  import { isInvalidPrimitive } from "../merge/isInvalidPrimitive";
2
- import { isPlainObject } from "../merge/utils";
2
+ import { isPlainObject } from "../guard/utils";
3
3
  import { tuplify } from "../array/tuplify";
4
4
  import { mergeArrays } from "../merge/mergeArrays";
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { isPlainObject } from "../merge/utils";
1
+ import { isPlainObject } from "../guard/utils";
2
2
  import { filterValidPrimitiveArrayValues } from "../merge/filterValidPrimitiveArrayValues";
3
3
  export function mergeArrays(arrays, options) {
4
4
  const merged = arrays.flat();
@@ -0,0 +1 @@
1
+ export * from "./replace";
@@ -0,0 +1 @@
1
+ export * from "./replace";
@@ -0,0 +1,7 @@
1
+ import type { FlatObject } from "../../src";
2
+ /**
3
+ * Replaces a single deeply nested value, addressed by a dot‑notation path, and
4
+ * returns a new object — the input is left untouched. The `value` type is
5
+ * derived from {@link FlatObject}, so it must match the type at `key`.
6
+ */
7
+ export declare function replace<TObject, TKey extends keyof FlatObject<TObject> & string>(object: TObject, key: TKey, value: FlatObject<TObject>[TKey]): TObject;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Replaces a single deeply nested value, addressed by a dot‑notation path, and
3
+ * returns a new object — the input is left untouched. The `value` type is
4
+ * derived from {@link FlatObject}, so it must match the type at `key`.
5
+ */
6
+ export function replace(object, key, value) {
7
+ return setDeep(object, key.split("."), value);
8
+ }
9
+ /**
10
+ * Immutably sets `value` at the dot‑notation `path`, cloning every container
11
+ * along the way. Numeric segments create/clone arrays, everything else objects,
12
+ * so a single element or key can be replaced without touching its siblings.
13
+ */
14
+ function setDeep(target, path, value) {
15
+ const [head, ...rest] = path;
16
+ const clone = Array.isArray(target)
17
+ ? [...target]
18
+ : { ...target };
19
+ if (rest.length === 0) {
20
+ clone[head] = value;
21
+ return clone;
22
+ }
23
+ const child = target?.[head];
24
+ const nextSegmentIsIndex = /^\d+$/.test(rest[0]);
25
+ clone[head] = setDeep(child ?? (nextSegmentIsIndex ? [] : {}), rest, value);
26
+ return clone;
27
+ }
@@ -0,0 +1,14 @@
1
+ import type { IsPlainObject } from "../types/IsPlainObject";
2
+ /**
3
+ * Recursively builds a union of all nested property paths in dot‑notation.
4
+ * Only plain objects are traversed; primitives, arrays, and functions
5
+ * produce their key directly without recursion.
6
+ *
7
+ * @example ```tsx
8
+ * { a: string, b: { c: { d: number } } }
9
+ * // "a" | "b.c.d"
10
+ * ```
11
+ */
12
+ export type DotPaths<TObject> = {
13
+ [TKey in keyof TObject]-?: IsPlainObject<TObject[TKey]> extends true ? (TKey & string) | `${TKey & string}.${DotPaths<TObject[TKey]>}` : TKey & string;
14
+ }[keyof TObject];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import type { IsPlainObject } from "../types/IsPlainObject";
2
+ /**
3
+ * Recursively builds dot‑notation paths, including numeric indices for arrays.
4
+ *
5
+ * @typeParam T - The object or array type to extract paths from.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * type Example = {
10
+ * users: [
11
+ * { name: string }
12
+ * ];
13
+ * };
14
+ *
15
+ * type Paths = DotPathsWithArrayIndex<Example>;
16
+ * // "users" | "users.0" | "users.0.name"
17
+ * ```
18
+ */
19
+ export type DotPathsWithArrayIndex<TObject> = TObject extends unknown[] ? TObject extends (infer TElement)[] ? TElement extends unknown[] ? `${number}` | `${number}.${DotPathsWithArrayIndex<TElement>}` : IsPlainObject<TElement> extends true ? `${number}` | `${number}.${DotPathsWithArrayIndex<TElement>}` : `${number}` : never : {
20
+ [TKey in keyof TObject]-?: TObject[TKey] extends unknown[] ? (TKey & string) | `${TKey & string}.${DotPathsWithArrayIndex<TObject[TKey]>}` : IsPlainObject<TObject[TKey]> extends true ? (TKey & string) | `${TKey & string}.${DotPathsWithArrayIndex<TObject[TKey]>}` : TKey & string;
21
+ }[keyof TObject];
@@ -0,0 +1,59 @@
1
+ import type { IsPlainObject } from "../types/IsPlainObject";
2
+ /**
3
+ * Collapses a union of objects into a single intersected object so that the
4
+ * per‑key results below merge into one flat lookup map instead of a union.
5
+ */
6
+ type UnionToIntersection<TUnion> = (TUnion extends unknown ? (arg: TUnion) => void : never) extends (arg: infer TIntersection) => void ? TIntersection : never;
7
+ /**
8
+ * Produces a flattened object type where keys are dot‑notation paths and
9
+ * values are the corresponding values. Both intermediate paths (objects and
10
+ * arrays) and leaf paths are emitted, so a whole nested object/array can be
11
+ * addressed just as safely as a leaf. Arrays are descended using a generic
12
+ * numeric index (`${number}`), so element paths remain type‑safe.
13
+ *
14
+ * @typeParam T - The object type to flatten.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * type Example = {
19
+ * a: string;
20
+ * b: { c: number };
21
+ * items: { id: string }[];
22
+ * };
23
+ *
24
+ * type Flat = FlatObject<Example>;
25
+ * // {
26
+ * // "a": string;
27
+ * // "b": { c: number };
28
+ * // "b.c": number;
29
+ * // "items": { id: string }[];
30
+ * // [k: `items.${number}`]: { id: string };
31
+ * // [k: `items.${number}.id`]: string;
32
+ * // }
33
+ * ```
34
+ */
35
+ export type FlatObject<T> = T extends readonly (infer TElement)[] ? IsPlainObject<TElement> extends true ? {
36
+ [Index in `${number}`]: TElement;
37
+ } & {
38
+ [SubKey in keyof FlatObject<TElement> & string as `${number}.${SubKey}`]: FlatObject<TElement>[SubKey];
39
+ } : TElement extends readonly unknown[] ? {
40
+ [Index in `${number}`]: TElement;
41
+ } & {
42
+ [SubKey in keyof FlatObject<TElement> & string as `${number}.${SubKey}`]: FlatObject<TElement>[SubKey];
43
+ } : {
44
+ [Index in `${number}`]: TElement;
45
+ } : FlatObjectFromKeys<Required<T>>;
46
+ type FlatObjectFromKeys<T> = UnionToIntersection<{
47
+ [Key in keyof T & string]: IsPlainObject<T[Key]> extends true ? {
48
+ [FlatKey in Key]: T[Key];
49
+ } & {
50
+ [SubKey in keyof FlatObject<T[Key]> & string as `${Key}.${SubKey}`]: FlatObject<T[Key]>[SubKey];
51
+ } : T[Key] extends readonly unknown[] ? {
52
+ [FlatKey in Key]: T[Key];
53
+ } & {
54
+ [SubKey in keyof FlatObject<T[Key]> & string as `${Key}.${SubKey}`]: FlatObject<T[Key]>[SubKey];
55
+ } : {
56
+ [FlatKey in Key]: T[Key];
57
+ };
58
+ }[keyof T & string]>;
59
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Determines whether a type is a plain object suitable for recursive traversal.
3
+ *
4
+ * A "plain object" in this context means:
5
+ * - It is an object type
6
+ * - It is **not** an array
7
+ * - It is **not** a function
8
+ *
9
+ * This prevents recursion from descending into prototypes of arrays, functions,
10
+ * primitives, or built‑in objects, ensuring that only object literals are walked.
11
+ *
12
+ * @typeParam T - The type being checked.
13
+ * @returns `true` if `TObject` is a non‑array, non‑function object; otherwise `false`.
14
+ */
15
+ export type IsPlainObject<TObject> = TObject extends object ? TObject extends unknown[] ? false : TObject extends (...args: unknown[]) => unknown ? false : true : false;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { IsPlainObject } from "../types/IsPlainObject";
2
+ /**
3
+ * Extracts only leaf property paths (deepest keys) in dot‑notation.
4
+ *
5
+ * @typeParam T - The object type whose leaf paths should be extracted.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * type Example = {
10
+ * a: string;
11
+ * b: { c: { d: number } };
12
+ * };
13
+ *
14
+ * type Paths = LeafDotPaths<Example>;
15
+ * // "a" | "b.c.d"
16
+ * ```
17
+ */
18
+ export type LeafDotPaths<TObject> = {
19
+ [TKey in keyof TObject]-?: IsPlainObject<TObject[TKey]> extends true ? `${TKey & string}.${LeafDotPaths<TObject[TKey]>}` : TKey & string;
20
+ }[keyof TObject];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export * from "./DeepPartial";
2
+ export * from "./DotPaths";
3
+ export * from "./DotPathsWithArrayIndex";
4
+ export * from "./FlatObject";
5
+ export * from "./IsPlainObject";
6
+ export * from "./LeafDotPaths";
@@ -0,0 +1,6 @@
1
+ export * from "./DeepPartial";
2
+ export * from "./DotPaths";
3
+ export * from "./DotPathsWithArrayIndex";
4
+ export * from "./FlatObject";
5
+ export * from "./IsPlainObject";
6
+ export * from "./LeafDotPaths";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1nkvi/utils",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Helper functions",
5
5
  "keywords": [
6
6
  "merge"
File without changes
File without changes