@1nkvi/utils 0.3.0 → 0.4.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
@@ -1,15 +1,30 @@
1
1
  # @1nkvi/utils
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@1nkvi/utils.svg)](https://www.npmjs.com/package/@1nkvi/utils)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@1nkvi/utils.svg)](https://www.npmjs.com/package/@1nkvi/utils)
5
+ [![types](https://img.shields.io/npm/types/@1nkvi/utils.svg)](https://www.npmjs.com/package/@1nkvi/utils)
6
+ [![license](https://img.shields.io/npm/l/@1nkvi/utils.svg)](./LICENSE)
7
+
8
+ Type-safe utility functions for the common scenarios that occur when working with objects — deep merging, immutable updates
9
+ by dot-notation path, and dot-path utility types — plus a handful of array, map, randomness, and type-guard helpers to
10
+ round things out.
11
+
12
+ - 🧩 **Fully typed** — written in TypeScript; ships its own declarations.
13
+ - 🌳 **Tree-shakeable** — side-effect free, so bundlers drop what you don't import.
14
+ - 🪶 **Zero runtime dependencies.**
15
+
16
+ ## Requirements
17
+
18
+ - **ESM-only.** The package ships only an `import` entry — use it from ESM (or a bundler). `require("@1nkvi/utils")`
19
+ is not supported.
20
+ - **Node ≥ 24.**
21
+
22
+ ## Install
23
+
3
24
  ```shell
4
25
  pnpm i @1nkvi/utils
5
26
  ```
6
27
 
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.
12
-
13
28
  ## Changelog
14
29
 
15
30
  [Changelog link](./CHANGELOG.md)
@@ -19,8 +34,8 @@ types.
19
34
  ```ts
20
35
  import { merge } from "@1nkvi/utils"
21
36
 
22
- merge([{ id: 1 }, { name: "Ada" }, { name: "Ada Lovelace" }])
23
- // → { id: 1, name: "Ada Lovelace" }
37
+ merge([{ id: 1 }, { name: "Hello" }, { name: "World" }])
38
+ // → { id: 1, name: "World" }
24
39
  ```
25
40
 
26
41
  ## Modules
@@ -33,4 +48,5 @@ merge([{ id: 1 }, { name: "Ada" }, { name: "Ada Lovelace" }])
33
48
  | [merge](./docs/merge.md) | Deeply `merge` partial objects, `mergeArrays` with de-duplication, and `filterValidPrimitiveArrayValues`, all skipping "empty" values. |
34
49
  | [object](./docs/object.md) | `replace` a single deeply nested value by dot-notation path — immutably and type-safely, without touching its siblings. |
35
50
  | [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`. |
51
+ | [types](./docs/types.md) | Utility types for nested objects: `DeepPartial`, `DotPaths`, `LeafDotPaths`, `DotPathsWithArrayIndex`, `FlatObject`, `IsPlainObject`, plus `LooseString` for string-literal autocomplete. |
52
+ | [window](./docs/window.md) | Browser DOM helpers: `getCssProperty` reads a computed CSS custom property from an element (defaults to `<html>`). |
@@ -5,3 +5,4 @@ export * from "./map";
5
5
  export * from "./object";
6
6
  export * from "./random";
7
7
  export * from "./types";
8
+ export * from "./window";
@@ -5,3 +5,4 @@ export * from "./map";
5
5
  export * from "./object";
6
6
  export * from "./random";
7
7
  export * from "./types";
8
+ export * from "./window";
@@ -10,5 +10,5 @@ import type { IsPlainObject } from "../types/IsPlainObject";
10
10
  * ```
11
11
  */
12
12
  export type DotPaths<TObject> = {
13
- [TKey in keyof TObject]: IsPlainObject<TObject[TKey]> extends true ? (TKey & string) | `${TKey & string}.${DotPaths<TObject[TKey]>}` : TKey & string;
13
+ [TKey in keyof TObject]-?: IsPlainObject<TObject[TKey]> extends true ? (TKey & string) | `${TKey & string}.${DotPaths<TObject[TKey]>}` : TKey & string;
14
14
  }[keyof TObject];
@@ -17,5 +17,5 @@ import type { IsPlainObject } from "../types/IsPlainObject";
17
17
  * ```
18
18
  */
19
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;
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
21
  }[keyof TObject];
@@ -42,7 +42,8 @@ export type FlatObject<T> = T extends readonly (infer TElement)[] ? IsPlainObjec
42
42
  [SubKey in keyof FlatObject<TElement> & string as `${number}.${SubKey}`]: FlatObject<TElement>[SubKey];
43
43
  } : {
44
44
  [Index in `${number}`]: TElement;
45
- } : UnionToIntersection<{
45
+ } : FlatObjectFromKeys<Required<T>>;
46
+ type FlatObjectFromKeys<T> = UnionToIntersection<{
46
47
  [Key in keyof T & string]: IsPlainObject<T[Key]> extends true ? {
47
48
  [FlatKey in Key]: T[Key];
48
49
  } & {
@@ -16,5 +16,5 @@ import type { IsPlainObject } from "../types/IsPlainObject";
16
16
  * ```
17
17
  */
18
18
  export type LeafDotPaths<TObject> = {
19
- [TKey in keyof TObject]: IsPlainObject<TObject[TKey]> extends true ? `${TKey & string}.${LeafDotPaths<TObject[TKey]>}` : TKey & string;
19
+ [TKey in keyof TObject]-?: IsPlainObject<TObject[TKey]> extends true ? `${TKey & string}.${LeafDotPaths<TObject[TKey]>}` : TKey & string;
20
20
  }[keyof TObject];
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Allows user to insert any `string` but also provides autocomplete for `TType`
3
+ * @example ```tsx
4
+ * type Dark = "dark"|"light"
5
+ *
6
+ * const works: LooseString<Dark> = "dark"
7
+ * const alsoWorks: LooseString<Dark> = "system"
8
+ * ```
9
+ */
10
+ export type LooseString<TType extends string> = TType | (string & {});
@@ -4,3 +4,4 @@ export * from "./DotPathsWithArrayIndex";
4
4
  export * from "./FlatObject";
5
5
  export * from "./IsPlainObject";
6
6
  export * from "./LeafDotPaths";
7
+ export * from "./LooseString";
@@ -4,3 +4,4 @@ export * from "./DotPathsWithArrayIndex";
4
4
  export * from "./FlatObject";
5
5
  export * from "./IsPlainObject";
6
6
  export * from "./LeafDotPaths";
7
+ export * from "./LooseString";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Retrieves css property based on the input.
3
+ * @param propertyName full name of css property (e.g. `--breakpoint-lg`)
4
+ * @param ref optional reference to html element. If not provided, root document is used
5
+ * @remarks resulting string doesnt resolve calculations. If css variable contains e.g. `calc(2rem + 5%)`, the output will be this, not resulting value
6
+ *
7
+ * @example ```tsx
8
+ * getCssProperty("--breakpoint-lg") // 64rem
9
+ * getCssProperty("--radius-sm") // calc(0.625rem - 4px)
10
+ * ```
11
+ */
12
+ export declare function getCssProperty(propertyName: string, ref?: HTMLElement | null): string;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Retrieves css property based on the input.
3
+ * @param propertyName full name of css property (e.g. `--breakpoint-lg`)
4
+ * @param ref optional reference to html element. If not provided, root document is used
5
+ * @remarks resulting string doesnt resolve calculations. If css variable contains e.g. `calc(2rem + 5%)`, the output will be this, not resulting value
6
+ *
7
+ * @example ```tsx
8
+ * getCssProperty("--breakpoint-lg") // 64rem
9
+ * getCssProperty("--radius-sm") // calc(0.625rem - 4px)
10
+ * ```
11
+ */
12
+ export function getCssProperty(propertyName, ref) {
13
+ const el = ref ?? document.documentElement;
14
+ return window.getComputedStyle(el).getPropertyValue(propertyName);
15
+ }
@@ -0,0 +1 @@
1
+ export * from "./getCssProperty";
@@ -0,0 +1 @@
1
+ export * from "./getCssProperty";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1nkvi/utils",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Helper functions",
5
5
  "keywords": [
6
6
  "merge"
@@ -1,6 +0,0 @@
1
- /**
2
- * Expects json object. Walks through the children and makes all keys optional
3
- */
4
- export type DeepPartial<T> = T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends object ? {
5
- [K in keyof T]?: DeepPartial<T[K]>;
6
- } : T;
@@ -1,4 +0,0 @@
1
- export declare function isPlainObject(v: unknown): v is Record<string, unknown>;
2
- export declare function isEmptyObject(v: unknown): v is object;
3
- export declare function isEmptyArray(v: unknown): v is Array<unknown>;
4
- export declare function isInvalidNumber(v: unknown): boolean;
@@ -1,14 +0,0 @@
1
- export function isPlainObject(v) {
2
- return typeof v === "object" && v !== null && !Array.isArray(v);
3
- }
4
- export function isEmptyObject(v) {
5
- if (!isPlainObject(v))
6
- return false;
7
- return Object.keys(v).length === 0;
8
- }
9
- export function isEmptyArray(v) {
10
- return Array.isArray(v) && v.length === 0;
11
- }
12
- export function isInvalidNumber(v) {
13
- return typeof v === "number" && (!Number.isFinite(v) || Number.isNaN(v));
14
- }