@web-ts-toolkit/utils 0.43.0 → 0.44.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 +138 -7
- package/index.d.mts +398 -8
- package/index.d.ts +398 -8
- package/index.js +352 -82
- package/index.mjs +351 -82
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,13 +8,12 @@ Shared collection, object, async, and URL helpers used across the workspace.
|
|
|
8
8
|
pnpm add @web-ts-toolkit/utils
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Requires Node `>=22`. Import from the package root with canonical named
|
|
12
|
+
imports; there is no default export and no public subpath:
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- URL helpers such as `normalizeUrlPath(...)`
|
|
17
|
-
- async helpers such as `mapValuesAsync(...)`
|
|
14
|
+
```ts
|
|
15
|
+
import { get, normalizeUrlPath, parseBooleanString } from '@web-ts-toolkit/utils';
|
|
16
|
+
```
|
|
18
17
|
|
|
19
18
|
## Quick Start
|
|
20
19
|
|
|
@@ -69,9 +68,141 @@ parseBooleanString('true', false);
|
|
|
69
68
|
- string helpers: `startCase`, `upperCase`
|
|
70
69
|
- guards: `isArray`, `isPlainObject`, `isString`, `isPromise`
|
|
71
70
|
- URL helpers: `addLeadingSlash`, `removeConsecutiveSlashesFromUrl`, `normalizeUrlPath`
|
|
71
|
+
- async helpers: `mapValuesAsync`, `toAsyncFn`
|
|
72
|
+
- misc: `castArray`, `arrayToRecord`, `mapValues`, `noop`, `padEnd`, `parseBooleanString`
|
|
73
|
+
|
|
74
|
+
## Path Grammar And Mutation Rules
|
|
75
|
+
|
|
76
|
+
`get`, `set`, `pick`, and `omit` accept a `PropertyPath`: dot segments
|
|
77
|
+
(`'a.b'`), bare brackets (`'a[0]'`), quoted brackets (`'a["b.c"]'`), or
|
|
78
|
+
segment arrays (`['a', 'b']`).
|
|
79
|
+
|
|
80
|
+
- Key identity is literal: string segments are never coerced, so `'01'`
|
|
81
|
+
and `'1'` address different properties, and digit keys beyond
|
|
82
|
+
`MAX_SAFE_INTEGER` never round. Only canonical indices (`'0'`, `'1'`,
|
|
83
|
+
… with no leading zeros) address array slots; `'a[01]'` addresses an
|
|
84
|
+
own `'01'` property. Empty quoted keys, escaped quotes, empty dot
|
|
85
|
+
segments, and malformed brackets are unspecified (no Lodash parity).
|
|
86
|
+
- Mutation segments `__proto__`, `constructor`, and `prototype` (quoted
|
|
87
|
+
or not) are rejected before any write: `set` returns its target
|
|
88
|
+
unchanged and `omit`/`deletePath` are no-ops.
|
|
89
|
+
- In `pick`/`omit`, a flat string array is a **list** of paths
|
|
90
|
+
(`pick(o, ['a', 'b'])` picks keys `a` and `b`); pass a nested array for
|
|
91
|
+
a single segmented path (`pick(o, [['a', 'b']])` picks `a.b`).
|
|
92
|
+
- Reads follow the prototype chain; `get` returns `defaultValue` for a
|
|
93
|
+
`null`/`undefined` intermediate or an `undefined` leaf. Writes never
|
|
94
|
+
traverse inherited containers: an inherited member is shadowed with a
|
|
95
|
+
new own container (array for a following canonical index, plain object
|
|
96
|
+
otherwise) and the final write creates an own data property, bypassing
|
|
97
|
+
inherited setters. Use `hasOwn` when own-key presence matters.
|
|
98
|
+
- Dictionary builders (`groupBy`, `arrayToRecord`, `mapKeys`,
|
|
99
|
+
`mapValues`, `pickBy`, `omitBy`, `toStringRecord`) preserve arbitrary
|
|
100
|
+
string keys — including `__proto__` — as own data properties without
|
|
101
|
+
replacing the result prototype. Results keep `Object.prototype`
|
|
102
|
+
(never null-prototype).
|
|
103
|
+
|
|
104
|
+
## Mutation Versus Copying
|
|
105
|
+
|
|
106
|
+
- `set` mutates its target in place and returns it. `omit` never mutates
|
|
107
|
+
its input: it deep-clones first, then deletes from the clone.
|
|
108
|
+
- `assign` is a thin wrapper over native `Object.assign` (source getters
|
|
109
|
+
and target setters run); it is not a hardened untrusted-input copier.
|
|
110
|
+
- `orderBy`, `uniq`/`uniqBy`, `difference`, the `intersection` family,
|
|
111
|
+
and `flatten`/`flattenDeep` never mutate their inputs. Sorting and
|
|
112
|
+
deduplication are stable/first-occurrence: ties keep input order and
|
|
113
|
+
the first occurrence wins.
|
|
114
|
+
|
|
115
|
+
## Clone And Comparison Domains
|
|
116
|
+
|
|
117
|
+
`cloneDeep`, `isEqual`, and `isMatch` share one bounded domain:
|
|
118
|
+
|
|
119
|
+
- Supported: primitives (`NaN` equals itself), plain objects
|
|
120
|
+
(`null`/`Object.prototype`, plus `Object.create` graphs over plain
|
|
121
|
+
ancestors whose prototype is shared by reference), arrays (length,
|
|
122
|
+
holes, and extra own keys participate), `Date` (by time), and `RegExp`
|
|
123
|
+
(by source plus flags). Cycles and repeated references terminate and
|
|
124
|
+
stay shared within the clone.
|
|
125
|
+
- Functions and exotic values (`Map`/`Set`, class instances such as BSON
|
|
126
|
+
`ObjectId`) are opaque: nested occurrences are shared by reference,
|
|
127
|
+
never traversed, and distinct references are never equal. A top-level
|
|
128
|
+
exotic root passed to `cloneDeep` throws `TypeError` instead of
|
|
129
|
+
returning an alias, so `omit` on an uncloneable root throws before
|
|
130
|
+
deleting anything rather than deleting from your input.
|
|
131
|
+
- Comparison uses own enumerable string/symbol keys only: inherited
|
|
132
|
+
state is ignored and prototypes are not compared. `isMatch` requires
|
|
133
|
+
each own source key (including `undefined`-valued and symbol keys) to
|
|
134
|
+
exist as an own key on the target, so `isMatch({}, { a: undefined })`
|
|
135
|
+
is `false`; arrays use prefix semantics.
|
|
136
|
+
|
|
137
|
+
## Async Contracts
|
|
138
|
+
|
|
139
|
+
- `toAsyncFn` lifts sync results into a promise, but it is not a full
|
|
140
|
+
async-function boundary: a synchronous `throw` escapes synchronously
|
|
141
|
+
instead of becoming a rejection, and thenables (including foreign
|
|
142
|
+
thenables) are returned unchanged with identity preserved rather than
|
|
143
|
+
converted to native promises. When `fn` is absent, the wrapper resolves
|
|
144
|
+
`defaultValue`. `this` is forwarded.
|
|
145
|
+
- `mapValuesAsync` starts every callback eagerly with unbounded
|
|
146
|
+
parallelism (`Promise.all`): one rejection rejects the whole call, and
|
|
147
|
+
there is no concurrency limit, cancellation, or scheduler. Chunk the
|
|
148
|
+
input if downstream throttling is needed.
|
|
149
|
+
|
|
150
|
+
## Boolean Strings
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { parseBooleanString } from '@web-ts-toolkit/utils';
|
|
154
|
+
|
|
155
|
+
parseBooleanString('true'); // true
|
|
156
|
+
parseBooleanString('false'); // false
|
|
157
|
+
parseBooleanString('TRUE'); // false — exact match only, no case folding
|
|
158
|
+
parseBooleanString(''); // undefined — empty string falls back to the default
|
|
159
|
+
parseBooleanString('', false); // false — via the default
|
|
160
|
+
parseBooleanString(undefined, true); // true — missing input uses the default
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`parseBooleanString(str, defaultValue)` returns `true` only for the exact
|
|
164
|
+
string `'true'`, returns `false` for any other non-empty string, and falls
|
|
165
|
+
back to `defaultValue` (which is `undefined` when omitted) when the input
|
|
166
|
+
is `undefined` **or the empty string `''`**. Note that an Express-style
|
|
167
|
+
`?flag=` query value parses to `''` and therefore yields the default, not
|
|
168
|
+
`false`.
|
|
169
|
+
|
|
170
|
+
## URL Paths Are Pathname-Only
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { normalizeUrlPath } from '@web-ts-toolkit/utils';
|
|
174
|
+
|
|
175
|
+
normalizeUrlPath('api//users'); // '/api/users'
|
|
176
|
+
normalizeUrlPath('api//users/42'); // '/api/users/42'
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`normalizeUrlPath` composes route-path fragments: it collapses every run
|
|
180
|
+
of slashes and prepends a leading slash. The input must be a path
|
|
181
|
+
fragment — no scheme/host, query string, or fragment. Full URLs are out
|
|
182
|
+
of domain and are mangled rather than normalized
|
|
183
|
+
(`normalizeUrlPath('https://example.com//a')` yields
|
|
184
|
+
`'/https:/example.com/a'`; slash runs inside query/fragment values are
|
|
185
|
+
collapsed too). These helpers are route-path composition for workspace
|
|
186
|
+
routers, not WHATWG URL normalization and not a security sanitizer.
|
|
187
|
+
|
|
188
|
+
## Guards And Types
|
|
189
|
+
|
|
190
|
+
- `isBoolean`/`isNumber`/`isString` accept primitives only: boxed
|
|
191
|
+
instances such as `new Boolean(false)` return `false` and are never
|
|
192
|
+
narrowed to primitives.
|
|
193
|
+
- `flattenDeep<T>(input)` takes `unknown` (a non-array yields `[]`) and
|
|
194
|
+
`T` is an unchecked caller assertion — specify it explicitly
|
|
195
|
+
(`flattenDeep<number>(input)`) or narrow `unknown[]` yourself. Cyclic
|
|
196
|
+
arrays throw `TypeError`; shared (non-ancestor) subarrays flatten once
|
|
197
|
+
per occurrence. Wide and deeply nested inputs flatten iteratively
|
|
198
|
+
without `RangeError`.
|
|
199
|
+
- `intersectionBy`/`difference` ignore non-array value arguments, while
|
|
200
|
+
`intersection` treats a non-array secondary as empty (result `[]`).
|
|
201
|
+
`intersectionBy` evaluates each element's iteratee once per input array;
|
|
202
|
+
redundant-callback side effects are not preserved.
|
|
72
203
|
|
|
73
204
|
## Documentation
|
|
74
205
|
|
|
75
|
-
Full package documentation lives
|
|
206
|
+
Full package documentation lives on the published docs site:
|
|
76
207
|
|
|
77
208
|
- live docs: https://web-ts-toolkit.pages.dev/docs/packages/utils
|
package/index.d.mts
CHANGED
|
@@ -1,15 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure `value` starts with a `/`. Values that already start with `/` are
|
|
3
|
+
* returned unchanged; the empty string becomes `'/'`.
|
|
4
|
+
*/
|
|
1
5
|
declare function addLeadingSlash(value: string): string;
|
|
2
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Converts an array of strings to a lookup record.
|
|
9
|
+
*
|
|
10
|
+
* UTILS-01 contract: every entry becomes an own data property, including
|
|
11
|
+
* `__proto__` (which plain assignment would drop by attempting a prototype
|
|
12
|
+
* set). The result keeps the default `Object.prototype` prototype.
|
|
13
|
+
*/
|
|
3
14
|
declare function arrayToRecord(arr: string[]): Record<string, true>;
|
|
4
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Thin wrapper over native `Object.assign`: copies own enumerable
|
|
18
|
+
* string/symbol properties from each source onto `target` and returns
|
|
19
|
+
* `target`. Source getters and target setters run as normal JavaScript
|
|
20
|
+
* semantics dictate. This is a plain copy helper, not a hardened
|
|
21
|
+
* untrusted-input sanitizer.
|
|
22
|
+
*/
|
|
5
23
|
declare function assign<T extends object>(target: T, ...sources: unknown[]): T;
|
|
6
24
|
|
|
7
25
|
declare function castArray<T>(value: T | T[]): T[];
|
|
8
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Deep-clones a value within the UTILS-04 bounded domain.
|
|
29
|
+
*
|
|
30
|
+
* Supported: primitives, plain objects (`null`/`Object.prototype`),
|
|
31
|
+
* `Object.create` graphs over plain-object ancestors (prototype preserved
|
|
32
|
+
* by reference, own keys deep-cloned), arrays, `Date`, `RegExp`. Functions
|
|
33
|
+
* and exotic values nested inside a supported container (class instances
|
|
34
|
+
* such as BSON `ObjectId`, `Map`/`Set`) are preserved by reference as
|
|
35
|
+
* opaque leaves. A top-level exotic root throws `TypeError` instead of
|
|
36
|
+
* returning an alias.
|
|
37
|
+
* Cycles and repeated references are preserved (shared stays shared,
|
|
38
|
+
* detached from the original). Class instances, `Map`/`Set`, and other
|
|
39
|
+
* non-plain objects throw `TypeError` instead of returning an alias.
|
|
40
|
+
*/
|
|
9
41
|
declare function cloneDeep<T>(value: T): T;
|
|
10
42
|
|
|
11
43
|
declare function compact<T>(array: T[] | null | undefined): T[];
|
|
12
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Set difference.
|
|
47
|
+
*
|
|
48
|
+
* UTILS-08: exclusion membership is precomputed once into a `Set`
|
|
49
|
+
* (SameValueZero: NaN equals NaN, +0/-0 equal; objects by reference),
|
|
50
|
+
* matching the previous linear `arrayIncludes` scan. First-occurrence
|
|
51
|
+
* order, item references, and input non-mutation are preserved. Non-array
|
|
52
|
+
* `values` entries are ignored (preserved ignore-policy, consistent with
|
|
53
|
+
* `intersectionBy`; differs from `intersection`'s empty-on-non-array rule).
|
|
54
|
+
*/
|
|
13
55
|
declare function difference<T>(array: T[] | null | undefined, ...values: Array<T[] | null | undefined>): T[];
|
|
14
56
|
|
|
15
57
|
declare function eachRight<T>(collection: T[] | null | undefined, iteratee: (value: T, key: number, collection: T[]) => unknown): T[] | null | undefined;
|
|
@@ -21,47 +63,205 @@ declare function find<T>(collection: T[] | Record<string, T> | null | undefined,
|
|
|
21
63
|
|
|
22
64
|
declare function flatten<T>(array: Array<T | T[]> | null | undefined): T[];
|
|
23
65
|
|
|
24
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Recursively flatten nested arrays into a single flat array.
|
|
68
|
+
*
|
|
69
|
+
* Iterative implementation: uses an explicit frame stack instead of call-stack
|
|
70
|
+
* recursion and pushes leaves one at a time instead of spreading whole child
|
|
71
|
+
* results into `push`, so wide (many-leaf) and deeply nested inputs do not
|
|
72
|
+
* throw `RangeError`. Left-to-right ordering is preserved.
|
|
73
|
+
*
|
|
74
|
+
* Leaf behavior: any non-array value (including `undefined`, holes read as
|
|
75
|
+
* `undefined`, objects, and functions) is appended as-is. A non-array input
|
|
76
|
+
* returns `[]`. There are no size limits.
|
|
77
|
+
*
|
|
78
|
+
* Cycle policy: an array that contains itself, directly or transitively
|
|
79
|
+
* through its current ancestor chain, throws a `TypeError`. Legitimate
|
|
80
|
+
* repeated (shared but non-ancestor) subarrays are flattened once per
|
|
81
|
+
* occurrence, so `const sub = [1]; flattenDeep([sub, sub])` is `[1, 1]`.
|
|
82
|
+
*
|
|
83
|
+
* @param array The value to flatten; non-array inputs yield `[]`.
|
|
84
|
+
* @returns A new flat array of the leaf values, in left-to-right order.
|
|
85
|
+
* @throws {TypeError} When a cyclic array reference is detected.
|
|
86
|
+
*
|
|
87
|
+
* UTILS-09 typing note: `T` is an unchecked caller assertion, not an
|
|
88
|
+
* inferred or validated leaf type — the function cannot verify element
|
|
89
|
+
* types at runtime. Specify it explicitly for typed leaves (e.g.
|
|
90
|
+
* `flattenDeep<number>(input)`) or narrow the default `unknown[]`
|
|
91
|
+
* yourself. A fully inferred recursive `FlatArray`-style result type is
|
|
92
|
+
* deliberately deferred: it would need an arbitrary depth cap and could
|
|
93
|
+
* not stay sound for non-array inputs (which yield `[]`).
|
|
94
|
+
*/
|
|
95
|
+
declare function flattenDeep<T = unknown>(array: unknown): T[];
|
|
25
96
|
|
|
26
97
|
declare function forEach<T>(collection: T[] | null | undefined, iteratee: (value: T, key: number, collection: T[]) => unknown): T[] | null | undefined;
|
|
27
98
|
declare function forEach<T extends object>(collection: T | null | undefined, iteratee: (value: T[keyof T], key: string, collection: T) => unknown): T | null | undefined;
|
|
28
99
|
|
|
29
100
|
type PropertyPath = string | number | Array<string | number>;
|
|
30
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Read the value at `path`, returning `defaultValue` when unreachable.
|
|
104
|
+
*
|
|
105
|
+
* Supported path grammar (see `toPath` in `_internal.ts`): dot segments
|
|
106
|
+
* (`'a.b'`), bare brackets (`'a[0]'`), quoted brackets (`'a["b.c"]'`), and
|
|
107
|
+
* segment arrays (`['a', 'b']`). String segments keep literal identity
|
|
108
|
+
* (`'01'` ≠ `'1'`); only canonical indices address array slots.
|
|
109
|
+
*
|
|
110
|
+
* Reads follow the prototype chain; use `hasOwn` when own-key presence
|
|
111
|
+
* matters. A `null`/`undefined` intermediate or an `undefined` leaf yields
|
|
112
|
+
* `defaultValue`, so an explicit `undefined` value is indistinguishable
|
|
113
|
+
* from a missing path.
|
|
114
|
+
*/
|
|
115
|
+
|
|
31
116
|
declare function get<T = unknown>(object: unknown, path: PropertyPath, defaultValue?: T): T;
|
|
32
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Groups collection values by iteratee result.
|
|
120
|
+
*
|
|
121
|
+
* UTILS-01 contract: group names are ordinary string keys preserved as own
|
|
122
|
+
* data properties, including `__proto__`, `constructor`, `prototype`, and
|
|
123
|
+
* `toString`. The result keeps the default `Object.prototype` prototype;
|
|
124
|
+
* inherited members are never read as existing groups.
|
|
125
|
+
*/
|
|
33
126
|
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[]>;
|
|
34
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Own-property check (`Object.hasOwn`): inherited properties do not count,
|
|
130
|
+
* and `null`/`undefined` values safely return `false`.
|
|
131
|
+
*/
|
|
35
132
|
declare function hasOwn<TKey extends PropertyKey>(value: unknown, key: TKey): value is Record<TKey, unknown>;
|
|
36
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Set intersection.
|
|
136
|
+
*
|
|
137
|
+
* UTILS-08: each secondary array's membership is precomputed once into a
|
|
138
|
+
* `Set` (SameValueZero: NaN equals NaN, +0/-0 equal; objects by reference),
|
|
139
|
+
* matching the previous linear `arrayIncludes` scans. First-occurrence
|
|
140
|
+
* order (via `baseUniq`), item references, and input non-mutation are
|
|
141
|
+
* preserved.
|
|
142
|
+
*
|
|
143
|
+
* Nullish contract (parity decision, preserved as-is): a non-array first
|
|
144
|
+
* argument yields `[]`, and any non-array secondary empties the result
|
|
145
|
+
* (`every` requires `Array.isArray`). This strict rule differs from
|
|
146
|
+
* `intersectionBy`/`difference`, which ignore non-array values arguments.
|
|
147
|
+
* The divergence is documented here rather than silently unified;
|
|
148
|
+
* unification is deferred to UTILS-11.
|
|
149
|
+
*/
|
|
37
150
|
declare function intersection<T>(...arrays: Array<T[] | null | undefined>): T[];
|
|
38
151
|
|
|
39
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Intersection by iteratee with precomputed secondary membership.
|
|
154
|
+
*
|
|
155
|
+
* UTILS-08 performance contract:
|
|
156
|
+
* - Each element's iteratee is evaluated exactly once per input array
|
|
157
|
+
* (work proportional to total input length), not once per candidate per
|
|
158
|
+
* secondary. A 100-by-100 workload therefore invokes the callback ~200
|
|
159
|
+
* times, not 10,100 times as before. Callback invocation count is
|
|
160
|
+
* intentionally changed; side effects from redundant evaluation are not
|
|
161
|
+
* preserved.
|
|
162
|
+
* - Secondary projections are stored in `Set`s, which use SameValueZero
|
|
163
|
+
* membership (NaN equals NaN, +0/-0 equal; objects by reference),
|
|
164
|
+
* matching the previous `sameValueZero` scans (UTILS-05).
|
|
165
|
+
* - First-occurrence ordering and original item references are preserved;
|
|
166
|
+
* inputs are never mutated.
|
|
167
|
+
*
|
|
168
|
+
* Nullish contract (parity decision, preserved as-is): non-array arguments
|
|
169
|
+
* are dropped via `Array.isArray` filtering (same ignore-policy as
|
|
170
|
+
* `difference`), so a nullish secondary is ignored rather than emptying
|
|
171
|
+
* the result. This differs from `intersection`, which treats a non-array
|
|
172
|
+
* secondary as empty (result `[]`). The divergence is documented here
|
|
173
|
+
* rather than silently unified; unification is deferred to UTILS-11.
|
|
174
|
+
*/
|
|
175
|
+
type IntersectionByIteratee<T> = ((value: T) => unknown) | string | number;
|
|
176
|
+
/**
|
|
177
|
+
* Intersection by iteratee with precomputed secondary membership.
|
|
178
|
+
*
|
|
179
|
+
* UTILS-09: the result element type is inferred from the first array; the
|
|
180
|
+
* iteratee parameter is excluded from inference (`NoInfer`) so a callback
|
|
181
|
+
* never distorts the element type. Non-array secondary arguments are ignored
|
|
182
|
+
* at runtime (see below) and are accepted in the type for that reason.
|
|
183
|
+
*/
|
|
184
|
+
declare function intersectionBy<T>(array: readonly T[], ...args: Array<readonly unknown[] | IntersectionByIteratee<NoInfer<T>> | null | undefined>): T[];
|
|
185
|
+
declare function intersectionBy<T = unknown>(...args: Array<readonly T[] | IntersectionByIteratee<T> | null | undefined>): T[];
|
|
40
186
|
|
|
41
187
|
declare function isArray(value: unknown): value is unknown[];
|
|
42
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Whether a value is a primitive boolean.
|
|
191
|
+
*
|
|
192
|
+
* UTILS-09 contract change: boxed `Boolean` objects are no longer accepted.
|
|
193
|
+
* A boxed instance (e.g. `new Boolean(false)`) is a truthy object, not the
|
|
194
|
+
* primitive `false`, so narrowing it to `boolean` was unsound. Use
|
|
195
|
+
* `value instanceof Boolean` explicitly when boxed instances are intended.
|
|
196
|
+
*/
|
|
43
197
|
declare function isBoolean(value: unknown): value is boolean;
|
|
44
198
|
|
|
45
199
|
declare function isEmpty(value: unknown): boolean;
|
|
46
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Deep equality within the UTILS-05 bounded domain (aligned with UTILS-04).
|
|
203
|
+
*
|
|
204
|
+
* Supported: primitives (`NaN` equals itself), plain objects (own
|
|
205
|
+
* enumerable string/symbol keys only; inherited state ignored, prototypes
|
|
206
|
+
* not compared), arrays (length + holes + extra own keys), `Date` (by
|
|
207
|
+
* time), `RegExp` (by source + flags). Functions and exotic objects
|
|
208
|
+
* (`Map`/`Set`, class instances, etc.) compare by identity only, so
|
|
209
|
+
* distinct instances are never equal. Cyclic graphs terminate via
|
|
210
|
+
* pair-aware bookkeeping. See `deepEqual` in `_internal.ts` for the full
|
|
211
|
+
* contract.
|
|
212
|
+
*/
|
|
47
213
|
declare function isEqual(left: unknown, right: unknown): boolean;
|
|
48
214
|
|
|
49
215
|
declare function isFunction(value: unknown): value is (...args: unknown[]) => unknown;
|
|
50
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Partial matching within the UTILS-05 bounded domain.
|
|
219
|
+
*
|
|
220
|
+
* Every own enumerable string/symbol key of a plain `source` must exist
|
|
221
|
+
* as an own key on `object` and match recursively; extra keys on
|
|
222
|
+
* `object` are ignored. Absence is distinguished from `undefined`
|
|
223
|
+
* (`isMatch({}, { a: undefined })` is false). Arrays use prefix
|
|
224
|
+
* semantics. `Date`/`RegExp`/primitive/function/exotic sources fall back
|
|
225
|
+
* to `deepEqual` (identity for opaque types). See `partialMatch` in
|
|
226
|
+
* `_internal.ts` for the full contract.
|
|
227
|
+
*/
|
|
51
228
|
declare function isMatch(object: unknown, source: unknown): boolean;
|
|
52
229
|
|
|
53
230
|
declare function isNaNValue(value: unknown): boolean;
|
|
54
231
|
|
|
55
232
|
declare function isNil(value: unknown): value is null | undefined;
|
|
56
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Whether a value is a primitive number.
|
|
236
|
+
*
|
|
237
|
+
* UTILS-09 contract change: boxed `Number` objects are no longer accepted.
|
|
238
|
+
* A boxed instance (e.g. `new Number(0)`) is an object, not the primitive
|
|
239
|
+
* `0`, so narrowing it to `number` was unsound. Use
|
|
240
|
+
* `value instanceof Number` explicitly when boxed instances are intended.
|
|
241
|
+
*/
|
|
57
242
|
declare function isNumber(value: unknown): value is number;
|
|
58
243
|
|
|
59
244
|
declare function isObject(value: unknown): value is object;
|
|
60
245
|
|
|
61
246
|
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
62
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Thenable check: true for any non-null value whose `then` is a function.
|
|
250
|
+
*
|
|
251
|
+
* UTILS-07 contract: native promises and foreign/cross-realm thenables
|
|
252
|
+
* satisfy this; a throwing `then` accessor propagates its throw. It does
|
|
253
|
+
* not verify genuine promise semantics beyond a callable `then`.
|
|
254
|
+
*/
|
|
63
255
|
declare function isPromise<T = unknown>(value: unknown): value is PromiseLike<T>;
|
|
64
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Whether a value is a primitive string.
|
|
259
|
+
*
|
|
260
|
+
* UTILS-09 contract change: boxed `String` objects are no longer accepted.
|
|
261
|
+
* A boxed instance (e.g. `new String('')`) is an object, not the primitive
|
|
262
|
+
* `''`, so narrowing it to `string` was unsound. Use
|
|
263
|
+
* `value instanceof String` explicitly when boxed instances are intended.
|
|
264
|
+
*/
|
|
65
265
|
declare function isString(value: unknown): value is string;
|
|
66
266
|
|
|
67
267
|
declare function isUndefined(value: unknown): value is undefined;
|
|
@@ -70,37 +270,180 @@ declare function join(array: unknown[] | null | undefined, separator?: string):
|
|
|
70
270
|
|
|
71
271
|
declare function keys(value: unknown): string[];
|
|
72
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Map an array by a known element key: the result element type follows the
|
|
275
|
+
* property type (e.g. `map(users, 'name')` yields `string[]`).
|
|
276
|
+
*
|
|
277
|
+
* UTILS-09: deeper property paths (`'a.b'`) are not key types and fall
|
|
278
|
+
* through to the generic overload below, yielding an honest `unknown[]`
|
|
279
|
+
* instead of a fabricated inference. No speculative path-type machinery.
|
|
280
|
+
*/
|
|
281
|
+
declare function map<T, K extends keyof T>(collection: readonly T[] | null | undefined, iteratee: K): Array<T[K]>;
|
|
73
282
|
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[];
|
|
74
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Maps object keys through an iteratee.
|
|
286
|
+
*
|
|
287
|
+
* UTILS-01 contract: mapped keys are stored as own data properties, so a
|
|
288
|
+
* mapped `__proto__` with an object value does not replace the result
|
|
289
|
+
* prototype. The result keeps the default `Object.prototype` prototype.
|
|
290
|
+
* Last-write-wins on duplicate mapped keys; callback order follows
|
|
291
|
+
* `Object.keys` order.
|
|
292
|
+
*/
|
|
75
293
|
declare function mapKeys<TValue>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => string): Record<string, TValue>;
|
|
76
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Maps object values through an iteratee.
|
|
297
|
+
*
|
|
298
|
+
* UTILS-01 contract: keys are preserved as own data properties (including
|
|
299
|
+
* `__proto__` with object values). The result keeps the default
|
|
300
|
+
* `Object.prototype` prototype; callback order follows `Object.keys` order.
|
|
301
|
+
*/
|
|
77
302
|
declare function mapValues<TValue, TResult>(object: Record<string, TValue> | null | undefined, iteratee: (value: TValue, key: string, object: Record<string, TValue>) => TResult): Record<string, TResult>;
|
|
78
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Map an object's values through an async callback.
|
|
306
|
+
*
|
|
307
|
+
* UTILS-07 contract (current behavior, locked by tests): all callbacks
|
|
308
|
+
* start eagerly with unbounded parallelism (`Promise.all`), preserving
|
|
309
|
+
* key order in the result. There is no concurrency limit, cancellation,
|
|
310
|
+
* or scheduler; a single rejection (or sync callback throw) rejects the
|
|
311
|
+
* whole call. An opt-in concurrency option is deferred to a follow-up
|
|
312
|
+
* (see UTILS-07 decision) pending a concrete caller need.
|
|
313
|
+
*/
|
|
79
314
|
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>>;
|
|
80
315
|
|
|
81
316
|
declare function noop(): void;
|
|
82
317
|
|
|
318
|
+
/**
|
|
319
|
+
* UTILS-03: `paths` is one path or a list of paths. A flat string array is a
|
|
320
|
+
* LIST of paths (`omit(o, ['a', 'b'])` omits keys `a` and `b`), not one
|
|
321
|
+
* segmented path. Pass a nested array for a single segmented path:
|
|
322
|
+
* `omit(o, [['a', 'b']])` omits `a.b`. Key identity follows `toPath`.
|
|
323
|
+
*
|
|
324
|
+
* UTILS-04: `omit` never mutates its input. The input is deep-cloned first
|
|
325
|
+
* within the bounded clone domain (plain objects, `Object.create` graphs
|
|
326
|
+
* over plain data, arrays, `Date`, `RegExp`; functions and nested exotics
|
|
327
|
+
* such as `ObjectId`/`Map` preserved by reference as opaque leaves).
|
|
328
|
+
* A top-level unsupported root (class instance, `Map`/`Set`, etc.) throws
|
|
329
|
+
* `TypeError` before any deletion instead of returning an aliased clone
|
|
330
|
+
* that would delete from input-owned state.
|
|
331
|
+
*/
|
|
83
332
|
declare function omit<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
84
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Omits entries whose predicate returns true.
|
|
336
|
+
*
|
|
337
|
+
* UTILS-01 contract: kept keys are stored as own data properties (including
|
|
338
|
+
* `__proto__` with object values). The result keeps the default
|
|
339
|
+
* `Object.prototype` prototype; the input is never mutated.
|
|
340
|
+
*/
|
|
85
341
|
declare function omitBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
86
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Parse a string-encoded boolean with an explicit fallback.
|
|
345
|
+
*
|
|
346
|
+
* Returns `true` only for the exact string `'true'`. Any other non-empty
|
|
347
|
+
* string (`'false'`, `'TRUE'`, `'1'`, …) returns `false` — matching is
|
|
348
|
+
* case-sensitive and no trimming is applied. The empty string `''` is
|
|
349
|
+
* treated like missing input and yields `defaultValue` (which is
|
|
350
|
+
* `undefined` when omitted); it does NOT return `false`.
|
|
351
|
+
*
|
|
352
|
+
* Query-string note: an Express-style `?flag=` parses to `''` and therefore
|
|
353
|
+
* falls back to `defaultValue`, not `false`. Pass an explicit default when
|
|
354
|
+
* that distinction matters.
|
|
355
|
+
*/
|
|
87
356
|
declare function parseBooleanString(str: string | undefined, defaultValue?: boolean): boolean | undefined;
|
|
88
357
|
|
|
358
|
+
/**
|
|
359
|
+
* Sort a collection copy by iteratees with a stable tie-break.
|
|
360
|
+
*
|
|
361
|
+
* Ties keep their original relative order, and the input is never mutated
|
|
362
|
+
* (a copy is sorted). An unrecognized `orders` entry sorts ascending; a
|
|
363
|
+
* non-array collection yields `[]`.
|
|
364
|
+
*/
|
|
89
365
|
declare function orderBy<T>(collection: T[] | null | undefined, iteratees?: Array<string | number | ((value: T) => unknown)>, orders?: string[]): T[];
|
|
90
366
|
|
|
91
367
|
declare function padEnd(value: unknown, length?: number, chars?: string): string;
|
|
92
368
|
|
|
369
|
+
/**
|
|
370
|
+
* UTILS-03: `paths` is one path or a list of paths. A flat string array is a
|
|
371
|
+
* LIST of paths (`pick(o, ['a', 'b'])` picks keys `a` and `b`), not one
|
|
372
|
+
* segmented path. Pass a nested array for a single segmented path:
|
|
373
|
+
* `pick(o, [['a', 'b']])` picks `a.b`. Key identity follows `toPath`
|
|
374
|
+
* (literal `'01'`, quoted digit keys, canonical numeric indices).
|
|
375
|
+
*/
|
|
93
376
|
declare function pick<T extends object>(object: T, paths: PropertyPath | PropertyPath[]): Partial<T>;
|
|
94
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Picks entries whose predicate returns true.
|
|
380
|
+
*
|
|
381
|
+
* UTILS-01 contract: kept keys are stored as own data properties (including
|
|
382
|
+
* `__proto__`). The result keeps the default `Object.prototype` prototype;
|
|
383
|
+
* the input is never mutated.
|
|
384
|
+
*/
|
|
95
385
|
declare function pickBy<TValue>(object: Record<string, TValue> | null | undefined, predicate: (value: TValue, key: string, object: Record<string, TValue>) => boolean): Record<string, TValue>;
|
|
96
386
|
|
|
387
|
+
/**
|
|
388
|
+
* Normalize a route-path fragment: collapse consecutive slashes and ensure
|
|
389
|
+
* a leading slash (`'api//users'` → `'/api/users'`).
|
|
390
|
+
*
|
|
391
|
+
* Pathname-only contract: the input must be a path fragment without a
|
|
392
|
+
* scheme/host, query string, or fragment. Full URLs are out of domain —
|
|
393
|
+
* slash runs are collapsed everywhere, including `https://` (which becomes
|
|
394
|
+
* `https:/`) and inside query/fragment values, and a leading slash is
|
|
395
|
+
* always prepended. This composes workspace router paths; it is not WHATWG
|
|
396
|
+
* URL normalization and not a security sanitizer.
|
|
397
|
+
*/
|
|
97
398
|
declare function normalizeUrlPath(url: string): string;
|
|
98
399
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
400
|
+
/**
|
|
401
|
+
* Reduce an array to a single value with an explicit initial accumulator.
|
|
402
|
+
*
|
|
403
|
+
* UTILS-09: the with-initial and without-initial contracts are separate
|
|
404
|
+
* overloads (previously one ambiguous optional-accumulator signature). An
|
|
405
|
+
* empty collection with an initial value returns that value.
|
|
406
|
+
*/
|
|
407
|
+
declare function reduce<T, TResult>(collection: T[] | null | undefined, iteratee: (accumulator: TResult, value: T, key: number, collection: T[]) => TResult, accumulator: TResult): TResult;
|
|
408
|
+
/**
|
|
409
|
+
* Reduce a record to a single value with an explicit initial accumulator.
|
|
410
|
+
*/
|
|
411
|
+
declare function reduce<T, TResult>(collection: Record<string, T> | null | undefined, iteratee: (accumulator: TResult, value: T, key: string, collection: Record<string, T>) => TResult, accumulator: TResult): TResult;
|
|
412
|
+
/**
|
|
413
|
+
* Reduce an array without an initial value: the first element seeds the
|
|
414
|
+
* accumulator, so the accumulator and result share the element type. Throws
|
|
415
|
+
* `TypeError` on an empty collection (never silently yields `undefined`).
|
|
416
|
+
*/
|
|
417
|
+
declare function reduce<T>(collection: T[] | null | undefined, iteratee: (accumulator: T, value: T, key: number, collection: T[]) => T): T;
|
|
418
|
+
/**
|
|
419
|
+
* Reduce a record without an initial value: the first value seeds the
|
|
420
|
+
* accumulator. Throws `TypeError` on an empty collection.
|
|
421
|
+
*/
|
|
422
|
+
declare function reduce<T>(collection: Record<string, T> | null | undefined, iteratee: (accumulator: T, value: T, key: string, collection: Record<string, T>) => T): T;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Collapse every run of two or more `/` characters to a single `/`.
|
|
426
|
+
*
|
|
427
|
+
* Pathname-only helper (see `normalizeUrlPath`): runs are collapsed
|
|
428
|
+
* everywhere in the string, including a URL scheme (`'https://…'` becomes
|
|
429
|
+
* `'https:/…'`) and query/fragment values. Do not apply to full URLs.
|
|
430
|
+
*/
|
|
102
431
|
declare function removeConsecutiveSlashesFromUrl(url: string): string;
|
|
103
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Sets `value` at `path` of `object` and returns `object`.
|
|
435
|
+
*
|
|
436
|
+
* UTILS-02 contract: forbidden segments (`__proto__`, `constructor`,
|
|
437
|
+
* `prototype`) are rejected before any mutation. Intermediate segments reuse
|
|
438
|
+
* only own object containers; inherited containers are shadowed with a new
|
|
439
|
+
* own container (array when the next segment is numeric, plain object
|
|
440
|
+
* otherwise) so ancestors are never mutated. The final write creates an own
|
|
441
|
+
* data property, bypassing inherited setters when shadowing.
|
|
442
|
+
*
|
|
443
|
+
* UTILS-03 key identity: string segments keep their literal identity (`'01'`
|
|
444
|
+
* stays `'01'`, never index 1; digit keys beyond `MAX_SAFE_INTEGER` never
|
|
445
|
+
* round). Arrays are created only for canonical indices (see `toPath`).
|
|
446
|
+
*/
|
|
104
447
|
declare function set<T>(object: T, path: PropertyPath, value: unknown): T;
|
|
105
448
|
|
|
106
449
|
declare function startCase(value: unknown): string;
|
|
@@ -109,14 +452,61 @@ declare function sum(values: number[] | null | undefined): number;
|
|
|
109
452
|
|
|
110
453
|
declare function sumBy<T>(collection: T[] | null | undefined, iteratee: string | number | ((value: T, key: number, collection: T[]) => number | undefined)): number;
|
|
111
454
|
|
|
112
|
-
|
|
113
|
-
|
|
455
|
+
/**
|
|
456
|
+
* Wrap a function so sync results are lifted into a promise.
|
|
457
|
+
*
|
|
458
|
+
* UTILS-07 contract (current behavior, locked by tests):
|
|
459
|
+
* - This is NOT a full async-function boundary. A synchronous `throw`
|
|
460
|
+
* from `fn` escapes synchronously instead of becoming a rejection.
|
|
461
|
+
* - Thenable results (including foreign/cross-realm thenables) are
|
|
462
|
+
* returned unchanged with identity preserved; they are not converted
|
|
463
|
+
* into native promises. A throwing `then` accessor therefore throws
|
|
464
|
+
* synchronously during the `isPromise` check.
|
|
465
|
+
* - When `fn` is absent/null, the wrapper resolves `defaultValue` in a
|
|
466
|
+
* native promise. `this` is forwarded via `fn.apply`.
|
|
467
|
+
* - UTILS-09 gave this contract an explicit truthful result type (see the
|
|
468
|
+
* overloads); do not widen behavior here without maintainer approval.
|
|
469
|
+
*
|
|
470
|
+
* UTILS-09 typing note: the overloads below type that contract truthfully.
|
|
471
|
+
* A present `fn` yields `Promise<Awaited<TResult>> | PromiseLike<TResult>` —
|
|
472
|
+
* deliberately NOT a bare `Promise`, because thenables pass through with
|
|
473
|
+
* identity preserved (so `instanceof Promise` may be false). A synchronous
|
|
474
|
+
* `throw` is not expressible in the return type and stays documented above.
|
|
475
|
+
* An absent `fn` yields `Promise<TResult | undefined>` since an omitted
|
|
476
|
+
* `defaultValue` resolves `undefined`.
|
|
477
|
+
*/
|
|
478
|
+
declare function toAsyncFn<TArgs extends unknown[], TResult>(fn: (this: unknown, ...args: TArgs) => TResult | PromiseLike<TResult>, defaultValue?: TResult): (this: unknown, ...args: TArgs) => Promise<Awaited<TResult>> | PromiseLike<TResult>;
|
|
479
|
+
declare function toAsyncFn<TArgs extends unknown[], TResult>(fn: null | undefined, defaultValue?: TResult): (this: unknown, ...args: TArgs) => Promise<TResult | undefined>;
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Stringifies own values of a plain object.
|
|
483
|
+
*
|
|
484
|
+
* UTILS-01 contract: keys are preserved as own data properties (including
|
|
485
|
+
* `__proto__`, which plain assignment would drop for string values). The
|
|
486
|
+
* result keeps the default `Object.prototype` prototype; the input is never
|
|
487
|
+
* mutated.
|
|
488
|
+
*/
|
|
114
489
|
declare function toStringRecord(value: unknown): Record<string, string> | undefined;
|
|
115
490
|
|
|
491
|
+
/**
|
|
492
|
+
* Deduplicate an array keeping the first occurrence of each value.
|
|
493
|
+
*
|
|
494
|
+
* Membership is SameValueZero (`NaN` equals `NaN`, `+0`/`-0` equal; objects
|
|
495
|
+
* by reference). Never mutates the input; a non-array input yields `[]`.
|
|
496
|
+
*/
|
|
116
497
|
declare function uniq<T>(array: T[] | null | undefined): T[];
|
|
117
498
|
|
|
499
|
+
/**
|
|
500
|
+
* Dedup by iteratee.
|
|
501
|
+
*
|
|
502
|
+
* UTILS-08: `seen` membership uses a `Set` (SameValueZero: NaN equals NaN,
|
|
503
|
+
* +0/-0 equal; objects by reference), matching the previous linear
|
|
504
|
+
* `sameValueZero` scan. First-occurrence order, item references, and input
|
|
505
|
+
* non-mutation are preserved. The iteratee is still invoked exactly once
|
|
506
|
+
* per element.
|
|
507
|
+
*/
|
|
118
508
|
declare function uniqBy<T>(array: T[] | null | undefined, iteratee?: string | number | ((value: T, key: number, collection: T[]) => unknown)): T[];
|
|
119
509
|
|
|
120
510
|
declare function upperCase(value: unknown): string;
|
|
121
511
|
|
|
122
|
-
export { addLeadingSlash, arrayToRecord, assign, castArray, cloneDeep, compact, difference, eachRight, 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, join, 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 };
|
|
512
|
+
export { type PropertyPath, addLeadingSlash, arrayToRecord, assign, castArray, cloneDeep, compact, difference, eachRight, 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, join, 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 };
|