umsizi 0.4.0 → 0.6.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 +101 -0
- package/dist/index.d.ts +126 -1
- package/dist/index.js +150 -1
- package/dist/index.js.map +1 -1
- package/dist/next.d.ts +3 -2
- package/dist/next.js +10 -6
- package/dist/next.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -150,6 +150,45 @@ const user = typedFromEntries([
|
|
|
150
150
|
] as const);
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
+
#### `path`
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { path } from "umsizi";
|
|
157
|
+
|
|
158
|
+
path("profile.addresses[0].city");
|
|
159
|
+
// ["profile", "addresses", 0, "city"]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### `get`
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import { get } from "umsizi";
|
|
166
|
+
|
|
167
|
+
get(
|
|
168
|
+
{ profile: { addresses: [{ city: "Durban" }] } },
|
|
169
|
+
"profile.addresses[0].city",
|
|
170
|
+
);
|
|
171
|
+
// "Durban"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### `set`
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import { set } from "umsizi";
|
|
178
|
+
|
|
179
|
+
set({}, "profile.addresses[0].city", "Durban");
|
|
180
|
+
// { profile: { addresses: [{ city: "Durban" }] } }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### `hasPath`
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { hasPath } from "umsizi";
|
|
187
|
+
|
|
188
|
+
hasPath({ profile: { nickname: undefined } }, ["profile", "nickname"]);
|
|
189
|
+
// true
|
|
190
|
+
```
|
|
191
|
+
|
|
153
192
|
#### `pick`
|
|
154
193
|
|
|
155
194
|
```ts
|
|
@@ -198,6 +237,68 @@ if (hasOwn(user, key)) {
|
|
|
198
237
|
}
|
|
199
238
|
```
|
|
200
239
|
|
|
240
|
+
#### `isPlainObject`
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { isPlainObject } from "umsizi";
|
|
244
|
+
|
|
245
|
+
const payload: unknown = { id: "1" };
|
|
246
|
+
|
|
247
|
+
if (isPlainObject(payload)) {
|
|
248
|
+
payload.id;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### `isRecord`
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import { isRecord } from "umsizi";
|
|
256
|
+
|
|
257
|
+
const payload: unknown = { id: "1" };
|
|
258
|
+
|
|
259
|
+
if (isRecord(payload)) {
|
|
260
|
+
payload.id;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### `hasKeys`
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import { hasKeys } from "umsizi";
|
|
268
|
+
|
|
269
|
+
const user = { id: "1", role: "admin" } as const;
|
|
270
|
+
|
|
271
|
+
if (hasKeys(user, "id", "role")) {
|
|
272
|
+
user.id;
|
|
273
|
+
user.role;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### `requireKeys`
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
import { requireKeys } from "umsizi";
|
|
281
|
+
|
|
282
|
+
const user = { id: "1", role: "admin" } as const;
|
|
283
|
+
const ensured = requireKeys(user, "id", "role");
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
#### `assertKeys`
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
import { assertKeys } from "umsizi";
|
|
290
|
+
|
|
291
|
+
const user: { id?: string; role?: string } = {
|
|
292
|
+
id: "1",
|
|
293
|
+
role: "admin",
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
assertKeys(user, "id", "role");
|
|
297
|
+
|
|
298
|
+
user.id;
|
|
299
|
+
user.role;
|
|
300
|
+
```
|
|
301
|
+
|
|
201
302
|
#### `mapValues`
|
|
202
303
|
|
|
203
304
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
|
+
//#region src/core/assert-keys.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Asserts that a plain object has all of the requested own keys.
|
|
4
|
+
*
|
|
5
|
+
* Prefer the rest-key form for the strongest autocomplete and inference.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const user = { id: "1", role: "admin" } as const;
|
|
10
|
+
*
|
|
11
|
+
* assertKeys(user, "id", "role");
|
|
12
|
+
* user.id; // "1"
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
declare function assertKeys<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(value: T, firstKey: FirstKey, ...restKeys: RestKeys): asserts value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;
|
|
16
|
+
declare function assertKeys<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(value: T, keys: readonly [FirstKey, ...RestKeys]): asserts value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;
|
|
17
|
+
declare function assertKeys<T extends object>(value: T, keys: readonly (keyof T)[]): asserts value is T;
|
|
18
|
+
//#endregion
|
|
1
19
|
//#region src/core/types.d.ts
|
|
2
20
|
type StringKeyOf<T extends object> = Extract<keyof T, string>;
|
|
21
|
+
type PathSegment = string | number;
|
|
22
|
+
type ObjectPath = readonly PathSegment[];
|
|
23
|
+
type PathInput = string | ObjectPath;
|
|
3
24
|
type ObjectEntry<T extends object> = { [K in StringKeyOf<T>]: readonly [K, T[K]] }[StringKeyOf<T>];
|
|
4
25
|
type ObjectEntries<T extends object> = Array<ObjectEntry<T>>;
|
|
5
26
|
type EntryTuple = readonly [PropertyKey, unknown];
|
|
@@ -11,6 +32,8 @@ type ValueGuard<T extends object, S extends T[StringKeyOf<T>]> = (value: T[Strin
|
|
|
11
32
|
type MappedValues<T extends object, R> = { [K in StringKeyOf<T>]: R };
|
|
12
33
|
type FilteredValues<T extends object, S extends T[StringKeyOf<T>]> = Partial<{ [K in StringKeyOf<T>]: Extract<T[K], S> }>;
|
|
13
34
|
type CompactedObject<T extends object> = Partial<{ [K in StringKeyOf<T>]: Exclude<T[K], null | undefined> }>;
|
|
35
|
+
type PathValueAtSegment<T, K$1 extends PathSegment> = K$1 extends keyof T ? T[K$1] : K$1 extends number ? T extends readonly (infer U)[] ? U : T extends (infer U)[] ? U : never : never;
|
|
36
|
+
type PathValue<T, P extends ObjectPath> = P extends readonly [] ? T : P extends readonly [infer Head extends PathSegment, ...infer Tail extends ObjectPath] ? PathValueAtSegment<T, Head> extends never ? never : PathValue<PathValueAtSegment<T, Head>, Tail> : never;
|
|
14
37
|
//#endregion
|
|
15
38
|
//#region src/core/compact-object.d.ts
|
|
16
39
|
/**
|
|
@@ -45,6 +68,41 @@ declare function compactObject<T extends object>(object: T): CompactedObject<T>;
|
|
|
45
68
|
declare function filterValues<T extends object, S extends T[Extract<keyof T, string>]>(object: T, predicate: ValueGuard<T, S>): FilteredValues<T, S>;
|
|
46
69
|
declare function filterValues<T extends object>(object: T, predicate: ValuePredicate<T>): FilteredValues<T, T[Extract<keyof T, string>]>;
|
|
47
70
|
//#endregion
|
|
71
|
+
//#region src/core/get.d.ts
|
|
72
|
+
/**
|
|
73
|
+
* Reads a nested own property using a tuple path or dot/bracket notation.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const user = { profile: { addresses: [{ city: "Durban" }] } } as const;
|
|
78
|
+
*
|
|
79
|
+
* get(user, ["profile", "addresses", 0, "city"]);
|
|
80
|
+
* get(user, "profile.addresses[0].city");
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function get<T, const P extends ObjectPath>(object: T, path: P): PathValue<T, P> | undefined;
|
|
84
|
+
declare function get<T, const P extends ObjectPath, D>(object: T, path: P, defaultValue: D): Exclude<PathValue<T, P>, undefined> | D;
|
|
85
|
+
declare function get<T>(object: T, path: string): unknown;
|
|
86
|
+
declare function get<T, D>(object: T, path: string, defaultValue: D): D | unknown;
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/core/has-keys.d.ts
|
|
89
|
+
/**
|
|
90
|
+
* Checks whether a plain object has all of the requested own keys.
|
|
91
|
+
*
|
|
92
|
+
* Prefer the rest-key form for the strongest autocomplete and inference.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const user = { id: "1", role: "admin" } as const;
|
|
97
|
+
*
|
|
98
|
+
* hasKeys(user, "id", "role"); // true
|
|
99
|
+
* hasKeys(user, ["id", "role"] as const); // true
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function hasKeys<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(value: T, firstKey: FirstKey, ...restKeys: RestKeys): value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;
|
|
103
|
+
declare function hasKeys<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(value: T, keys: readonly [FirstKey, ...RestKeys]): value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;
|
|
104
|
+
declare function hasKeys<T extends object>(value: T, keys: readonly (keyof T)[]): value is T;
|
|
105
|
+
//#endregion
|
|
48
106
|
//#region src/core/has-own.d.ts
|
|
49
107
|
/**
|
|
50
108
|
* Checks whether an object has the given property as its own key.
|
|
@@ -64,6 +122,15 @@ declare function filterValues<T extends object>(object: T, predicate: ValuePredi
|
|
|
64
122
|
*/
|
|
65
123
|
declare function hasOwn<T extends object, K$1 extends PropertyKey>(object: T, key: K$1): key is Extract<K$1, keyof T>;
|
|
66
124
|
//#endregion
|
|
125
|
+
//#region src/core/has-path.d.ts
|
|
126
|
+
/**
|
|
127
|
+
* Checks whether a nested own-property path exists.
|
|
128
|
+
*
|
|
129
|
+
* A resolved `undefined` value still counts as existing as long as every
|
|
130
|
+
* segment is present as an own property.
|
|
131
|
+
*/
|
|
132
|
+
declare function hasPath(object: unknown, pathInput: PathInput): boolean;
|
|
133
|
+
//#endregion
|
|
67
134
|
//#region src/core/identity.d.ts
|
|
68
135
|
/**
|
|
69
136
|
* Returns the given value unchanged.
|
|
@@ -93,6 +160,25 @@ declare function identity<T>(value: T): T;
|
|
|
93
160
|
*/
|
|
94
161
|
declare function isEmpty(object: object): boolean;
|
|
95
162
|
//#endregion
|
|
163
|
+
//#region src/core/is-plain-object.d.ts
|
|
164
|
+
/**
|
|
165
|
+
* Checks whether a value is a plain object with a prototype of
|
|
166
|
+
* `Object.prototype` or `null`.
|
|
167
|
+
*
|
|
168
|
+
* Arrays, functions, boxed primitives, dates, maps, sets, and class instances
|
|
169
|
+
* all return `false`.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* const payload: unknown = { id: "1" };
|
|
174
|
+
*
|
|
175
|
+
* if (isPlainObject(payload)) {
|
|
176
|
+
* payload.id;
|
|
177
|
+
* }
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
declare function isPlainObject(value: unknown): value is Record<PropertyKey, unknown>;
|
|
181
|
+
//#endregion
|
|
96
182
|
//#region src/core/map-values.d.ts
|
|
97
183
|
/**
|
|
98
184
|
* Maps the values of an object's own enumerable string-keyed properties while
|
|
@@ -126,6 +212,18 @@ declare function omit<T extends object, const Keys extends readonly (keyof T)[]>
|
|
|
126
212
|
declare function omit<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(object: T, keys: readonly [FirstKey, ...RestKeys]): Omit<T, FirstKey | RestKeys[number]>;
|
|
127
213
|
declare function omit<T extends object>(object: T, keys: readonly (keyof T)[]): Partial<T>;
|
|
128
214
|
//#endregion
|
|
215
|
+
//#region src/core/path.d.ts
|
|
216
|
+
/**
|
|
217
|
+
* Converts dot/bracket notation into a normalized object path array.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* path("profile.addresses[0].city");
|
|
222
|
+
* // ["profile", "addresses", 0, "city"]
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
declare function path(input: PathInput): ObjectPath;
|
|
226
|
+
//#endregion
|
|
129
227
|
//#region src/core/pick.d.ts
|
|
130
228
|
/**
|
|
131
229
|
* Creates a new object containing only the selected own properties.
|
|
@@ -144,6 +242,33 @@ declare function pick<T extends object, const Keys extends readonly (keyof T)[]>
|
|
|
144
242
|
declare function pick<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(object: T, keys: readonly [FirstKey, ...RestKeys]): Pick<T, FirstKey | RestKeys[number]>;
|
|
145
243
|
declare function pick<T extends object>(object: T, keys: readonly (keyof T)[]): Partial<T>;
|
|
146
244
|
//#endregion
|
|
245
|
+
//#region src/core/require-keys.d.ts
|
|
246
|
+
/**
|
|
247
|
+
* Requires that a plain object has all of the requested own keys.
|
|
248
|
+
*
|
|
249
|
+
* Prefer the rest-key form for the strongest autocomplete and inference.
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```ts
|
|
253
|
+
* const user = { id: "1", role: "admin" } as const;
|
|
254
|
+
* const result = requireKeys(user, "id", "role");
|
|
255
|
+
*
|
|
256
|
+
* result.id; // "1"
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
declare function requireKeys<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(value: T, firstKey: FirstKey, ...restKeys: RestKeys): T & Required<Pick<T, FirstKey | RestKeys[number]>>;
|
|
260
|
+
declare function requireKeys<T extends object, const FirstKey extends keyof T, const RestKeys extends readonly (keyof T)[]>(value: T, keys: readonly [FirstKey, ...RestKeys]): T & Required<Pick<T, FirstKey | RestKeys[number]>>;
|
|
261
|
+
declare function requireKeys<T extends object>(value: T, keys: readonly (keyof T)[]): T;
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/core/set.d.ts
|
|
264
|
+
/**
|
|
265
|
+
* Returns a new object with the nested path set to the given value.
|
|
266
|
+
*
|
|
267
|
+
* Missing containers are created automatically. Only the updated path is
|
|
268
|
+
* cloned; untouched branches retain their existing references.
|
|
269
|
+
*/
|
|
270
|
+
declare function set<T extends object>(object: T, pathInput: PathInput, value: unknown): T;
|
|
271
|
+
//#endregion
|
|
147
272
|
//#region src/core/typed-entries.d.ts
|
|
148
273
|
/**
|
|
149
274
|
* Returns the own enumerable string-keyed entries of an object with preserved
|
|
@@ -194,5 +319,5 @@ declare function typedFromEntries<const T extends EntryTuples>(entries: T): Obje
|
|
|
194
319
|
*/
|
|
195
320
|
declare function typedKeys<T extends object>(object: T): Array<StringKeyOf<T>>;
|
|
196
321
|
//#endregion
|
|
197
|
-
export { compactObject, filterValues, hasOwn, identity, isEmpty, mapValues, omit, pick, typedEntries, typedFromEntries, typedKeys };
|
|
322
|
+
export { assertKeys, compactObject, filterValues, get, hasKeys, hasOwn, hasPath, identity, isEmpty, isPlainObject, isPlainObject as isRecord, mapValues, omit, path, pick, requireKeys, set, typedEntries, typedFromEntries, typedKeys };
|
|
198
323
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
//#region src/core/has-keys.ts
|
|
2
|
+
function hasKeys(value, firstKeyOrKeys, ...restKeys) {
|
|
3
|
+
if (value === null || typeof value !== "object") return false;
|
|
4
|
+
const prototype = Object.getPrototypeOf(value);
|
|
5
|
+
if (prototype !== Object.prototype && prototype !== null) return false;
|
|
6
|
+
const keys = Array.isArray(firstKeyOrKeys) ? firstKeyOrKeys : [firstKeyOrKeys, ...restKeys];
|
|
7
|
+
for (const key of keys) if (!Object.hasOwn(value, key)) return false;
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/core/require-keys.ts
|
|
13
|
+
function requireKeys(value, firstKeyOrKeys, ...restKeys) {
|
|
14
|
+
const keys = Array.isArray(firstKeyOrKeys) ? firstKeyOrKeys : [firstKeyOrKeys, ...restKeys];
|
|
15
|
+
if (hasKeys(value, keys)) return value;
|
|
16
|
+
const missingKeys = [];
|
|
17
|
+
if (value !== null && typeof value === "object") {
|
|
18
|
+
const prototype = Object.getPrototypeOf(value);
|
|
19
|
+
if (prototype === Object.prototype || prototype === null) {
|
|
20
|
+
for (const key of keys) if (!Object.hasOwn(value, key)) missingKeys.push(key);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (missingKeys.length === 0) missingKeys.push(...keys);
|
|
24
|
+
const label = missingKeys.length === 1 ? "key" : "keys";
|
|
25
|
+
throw new TypeError(`Missing required ${label}: ${missingKeys.map(String).join(", ")}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/core/assert-keys.ts
|
|
30
|
+
function assertKeys(value, firstKeyOrKeys, ...restKeys) {
|
|
31
|
+
requireKeys(value, firstKeyOrKeys, ...restKeys);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
1
35
|
//#region src/core/typed-keys.ts
|
|
2
36
|
/**
|
|
3
37
|
* Returns the own enumerable string keys of an object with preserved key types.
|
|
@@ -71,6 +105,65 @@ function hasOwn(object, key) {
|
|
|
71
105
|
return Object.hasOwn(object, key);
|
|
72
106
|
}
|
|
73
107
|
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/core/path.ts
|
|
110
|
+
const BRACKET_PATH_SEGMENT_PATTERN = /[^.[\]]+|\[(?:([^"'[\]]+)|(["'])(.*?)\2)\]/g;
|
|
111
|
+
function toPathSegment(value) {
|
|
112
|
+
return /^\d+$/.test(value) ? Number(value) : value;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Converts dot/bracket notation into a normalized object path array.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* path("profile.addresses[0].city");
|
|
120
|
+
* // ["profile", "addresses", 0, "city"]
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
function path(input) {
|
|
124
|
+
if (typeof input !== "string") return [...input];
|
|
125
|
+
const source = input;
|
|
126
|
+
const segments = [];
|
|
127
|
+
for (const match of source.matchAll(BRACKET_PATH_SEGMENT_PATTERN)) {
|
|
128
|
+
const [, bareSegment, , quotedSegment] = match;
|
|
129
|
+
const segment = quotedSegment ?? bareSegment ?? match[0];
|
|
130
|
+
if (segment !== "") segments.push(toPathSegment(segment));
|
|
131
|
+
}
|
|
132
|
+
return segments;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/core/get.ts
|
|
137
|
+
function hasMissingPathSegment(value, segment) {
|
|
138
|
+
return value === null || value === void 0 || typeof value !== "object" && typeof value !== "function" || !hasOwn(value, segment);
|
|
139
|
+
}
|
|
140
|
+
function get(object, pathInput, defaultValue) {
|
|
141
|
+
const segments = path(pathInput);
|
|
142
|
+
let current = object;
|
|
143
|
+
for (const segment of segments) {
|
|
144
|
+
if (hasMissingPathSegment(current, segment)) return defaultValue;
|
|
145
|
+
current = current[segment];
|
|
146
|
+
}
|
|
147
|
+
return current;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/core/has-path.ts
|
|
152
|
+
/**
|
|
153
|
+
* Checks whether a nested own-property path exists.
|
|
154
|
+
*
|
|
155
|
+
* A resolved `undefined` value still counts as existing as long as every
|
|
156
|
+
* segment is present as an own property.
|
|
157
|
+
*/
|
|
158
|
+
function hasPath(object, pathInput) {
|
|
159
|
+
let current = object;
|
|
160
|
+
for (const segment of path(pathInput)) {
|
|
161
|
+
if (current === null || current === void 0 || typeof current !== "object" && typeof current !== "function" || !hasOwn(current, segment)) return false;
|
|
162
|
+
current = current[segment];
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
|
|
74
167
|
//#endregion
|
|
75
168
|
//#region src/core/identity.ts
|
|
76
169
|
/**
|
|
@@ -108,6 +201,30 @@ function isEmpty(object) {
|
|
|
108
201
|
return true;
|
|
109
202
|
}
|
|
110
203
|
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/core/is-plain-object.ts
|
|
206
|
+
/**
|
|
207
|
+
* Checks whether a value is a plain object with a prototype of
|
|
208
|
+
* `Object.prototype` or `null`.
|
|
209
|
+
*
|
|
210
|
+
* Arrays, functions, boxed primitives, dates, maps, sets, and class instances
|
|
211
|
+
* all return `false`.
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```ts
|
|
215
|
+
* const payload: unknown = { id: "1" };
|
|
216
|
+
*
|
|
217
|
+
* if (isPlainObject(payload)) {
|
|
218
|
+
* payload.id;
|
|
219
|
+
* }
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
function isPlainObject(value) {
|
|
223
|
+
if (value === null || typeof value !== "object") return false;
|
|
224
|
+
const prototype = Object.getPrototypeOf(value);
|
|
225
|
+
return prototype === Object.prototype || prototype === null;
|
|
226
|
+
}
|
|
227
|
+
|
|
111
228
|
//#endregion
|
|
112
229
|
//#region src/core/map-values.ts
|
|
113
230
|
/**
|
|
@@ -147,6 +264,38 @@ function pick(object, firstKeyOrKeys, ...restKeys) {
|
|
|
147
264
|
return result;
|
|
148
265
|
}
|
|
149
266
|
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/core/set.ts
|
|
269
|
+
function isContainer(value) {
|
|
270
|
+
return typeof value === "object" && value !== null;
|
|
271
|
+
}
|
|
272
|
+
function createContainer(nextSegment) {
|
|
273
|
+
return typeof nextSegment === "number" ? [] : {};
|
|
274
|
+
}
|
|
275
|
+
function cloneContainer(value, nextSegment) {
|
|
276
|
+
if (Array.isArray(value)) return [...value];
|
|
277
|
+
if (isContainer(value)) return Object.assign(Object.create(Object.getPrototypeOf(value)), value);
|
|
278
|
+
return createContainer(nextSegment);
|
|
279
|
+
}
|
|
280
|
+
function setAtPath(current, segments, value) {
|
|
281
|
+
const [segment, ...rest] = segments;
|
|
282
|
+
const clone = cloneContainer(current, segment);
|
|
283
|
+
const existingValue = isContainer(current) || Array.isArray(current) ? current[segment] : void 0;
|
|
284
|
+
clone[segment] = rest.length === 0 ? value : setAtPath(existingValue, rest, value);
|
|
285
|
+
return clone;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Returns a new object with the nested path set to the given value.
|
|
289
|
+
*
|
|
290
|
+
* Missing containers are created automatically. Only the updated path is
|
|
291
|
+
* cloned; untouched branches retain their existing references.
|
|
292
|
+
*/
|
|
293
|
+
function set(object, pathInput, value) {
|
|
294
|
+
const segments = path(pathInput);
|
|
295
|
+
if (segments.length === 0) return object;
|
|
296
|
+
return setAtPath(object, segments, value);
|
|
297
|
+
}
|
|
298
|
+
|
|
150
299
|
//#endregion
|
|
151
300
|
//#region src/core/typed-entries.ts
|
|
152
301
|
/**
|
|
@@ -189,5 +338,5 @@ function typedFromEntries(entries) {
|
|
|
189
338
|
}
|
|
190
339
|
|
|
191
340
|
//#endregion
|
|
192
|
-
export { compactObject, filterValues, hasOwn, identity, isEmpty, mapValues, omit, pick, typedEntries, typedFromEntries, typedKeys };
|
|
341
|
+
export { assertKeys, compactObject, filterValues, get, hasKeys, hasOwn, hasPath, identity, isEmpty, isPlainObject, isPlainObject as isRecord, mapValues, omit, path, pick, requireKeys, set, typedEntries, typedFromEntries, typedKeys };
|
|
193
342
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["result: Partial<T>","result: Partial<T>"],"sources":["../src/core/typed-keys.ts","../src/core/compact-object.ts","../src/core/filter-values.ts","../src/core/has-own.ts","../src/core/identity.ts","../src/core/is-empty.ts","../src/core/map-values.ts","../src/core/omit.ts","../src/core/pick.ts","../src/core/typed-entries.ts","../src/core/typed-from-entries.ts"],"sourcesContent":["import type { StringKeyOf } from \"./types\";\n\n/**\n * Returns the own enumerable string keys of an object with preserved key types.\n *\n * This is a typed wrapper around `Object.keys`.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\" } as const;\n *\n * typedKeys(user); // [\"id\", \"name\"]\n * ```\n */\nexport function typedKeys<T extends object>(object: T): Array<StringKeyOf<T>> {\n\treturn Object.keys(object) as Array<StringKeyOf<T>>;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { CompactedObject } from \"./types\";\n\n/**\n * Creates a new object with all `null` and `undefined` values removed.\n *\n * Other falsy values such as `0`, `false`, `\"\"`, and `NaN` are preserved.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", nickname: null, active: false } as const;\n *\n * compactObject(user); // { id: \"1\", active: false }\n * ```\n */\nexport function compactObject<T extends object>(object: T): CompactedObject<T> {\n\tconst result = {} as CompactedObject<T>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst value = object[key];\n\n\t\tif (value != null) {\n\t\t\tresult[key] = value as Exclude<T[typeof key], null | undefined>;\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { FilteredValues, ValueGuard, ValuePredicate } from \"./types\";\n\n/**\n * Filters an object's own enumerable string-keyed properties by value.\n *\n * Supports both boolean predicates and type-guard predicates. The result type\n * remains partial because any property may be removed at runtime.\n *\n * @example\n * ```ts\n * const settings = { retries: 3, label: \"\", timeout: null } as const;\n *\n * filterValues(settings, (value) => value !== null);\n * // { retries: 3, label: \"\" }\n * ```\n */\nexport function filterValues<\n\tT extends object,\n\tS extends T[Extract<keyof T, string>],\n>(object: T, predicate: ValueGuard<T, S>): FilteredValues<T, S>;\nexport function filterValues<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): FilteredValues<T, T[Extract<keyof T, string>]>;\nexport function filterValues<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): FilteredValues<T, T[Extract<keyof T, string>]> {\n\tconst result = {} as FilteredValues<T, T[Extract<keyof T, string>]>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst value = object[key];\n\n\t\tif (predicate(value, key, object)) {\n\t\t\tresult[key] = value;\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * Checks whether an object has the given property as its own key.\n *\n * This is a typed wrapper around `Object.hasOwn` that narrows the provided key\n * when the check succeeds.\n *\n * @example\n * ```ts\n * const user = { id: \"1\" };\n * const key: string = \"id\";\n *\n * if (hasOwn(user, key)) {\n * user[key]; // key is narrowed to \"id\"\n * }\n * ```\n */\nexport function hasOwn<T extends object, K extends PropertyKey>(\n\tobject: T,\n\tkey: K,\n): key is Extract<K, keyof T> {\n\treturn Object.hasOwn(object, key);\n}\n","/**\n * Returns the given value unchanged.\n *\n * Useful as a default callback, a type-inference anchor, or a no-op\n * placeholder where a transform function is expected.\n *\n * @example\n * ```ts\n * identity(\"umsizi\"); // \"umsizi\"\n * ```\n */\nexport function identity<T>(value: T): T {\n\treturn value;\n}\n","/**\n * Returns `true` when an object has no own enumerable properties.\n *\n * Both string keys and symbol keys are considered. Non-enumerable properties\n * are ignored.\n *\n * @example\n * ```ts\n * isEmpty({}); // true\n * isEmpty({ id: \"1\" }); // false\n * ```\n */\nexport function isEmpty(object: object): boolean {\n\tif (Object.keys(object).length > 0) {\n\t\treturn false;\n\t}\n\n\tfor (const key of Object.getOwnPropertySymbols(object)) {\n\t\tif (Object.prototype.propertyIsEnumerable.call(object, key)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { MappedValues, ValueMapper } from \"./types\";\n\n/**\n * Maps the values of an object's own enumerable string-keyed properties while\n * preserving the original enumerable string-key set.\n *\n * @example\n * ```ts\n * const counts = { draft: 1, published: 2 };\n *\n * mapValues(counts, (value) => value * 2);\n * // { draft: 2, published: 4 }\n * ```\n */\nexport function mapValues<T extends object, R>(\n\tobject: T,\n\tmapper: ValueMapper<T, R>,\n): MappedValues<T, R> {\n\tconst result = {} as MappedValues<T, R>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tresult[key] = mapper(object[key], key, object);\n\t}\n\n\treturn result;\n}\n","/**\n * Creates a new object excluding the selected own enumerable properties.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\", role: \"admin\" } as const;\n *\n * omit(user, \"id\", \"name\"); // { role: \"admin\" }\n * omit(user, [\"role\"] as const); // { id: \"1\", name: \"Umsizi\" }\n * ```\n */\nexport function omit<T extends object, const Keys extends readonly (keyof T)[]>(\n\tobject: T,\n\t...keys: Keys\n): Omit<T, Keys[number]>;\nexport function omit<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tobject: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): Omit<T, FirstKey | RestKeys[number]>;\nexport function omit<T extends object>(\n\tobject: T,\n\tkeys: readonly (keyof T)[],\n): Partial<T>;\nexport function omit<T extends object>(\n\tobject: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): Partial<T> {\n\tconst keys = (\n\t\tArray.isArray(firstKeyOrKeys)\n\t\t\t? firstKeyOrKeys\n\t\t\t: [firstKeyOrKeys, ...restKeys]\n\t) as readonly (keyof T)[];\n\tconst omittedKeys = new Set<PropertyKey>(keys as readonly PropertyKey[]);\n\tconst result: Partial<T> = {};\n\n\tfor (const key of Reflect.ownKeys(object) as (keyof T)[]) {\n\t\tif (\n\t\t\tObject.prototype.propertyIsEnumerable.call(object, key) &&\n\t\t\t!omittedKeys.has(key)\n\t\t) {\n\t\t\t(result as T)[key] = object[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { hasOwn } from \"./has-own\";\n\n/**\n * Creates a new object containing only the selected own properties.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\", role: \"admin\" } as const;\n *\n * pick(user, \"name\"); // { name: \"Umsizi\" }\n * pick(user, [\"id\", \"role\"] as const); // { id: \"1\", role: \"admin\" }\n * ```\n */\nexport function pick<T extends object, const Keys extends readonly (keyof T)[]>(\n\tobject: T,\n\t...keys: Keys\n): Pick<T, Keys[number]>;\nexport function pick<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tobject: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): Pick<T, FirstKey | RestKeys[number]>;\nexport function pick<T extends object>(\n\tobject: T,\n\tkeys: readonly (keyof T)[],\n): Partial<T>;\nexport function pick<T extends object>(\n\tobject: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): Partial<T> {\n\tconst keys = (\n\t\tArray.isArray(firstKeyOrKeys)\n\t\t\t? firstKeyOrKeys\n\t\t\t: [firstKeyOrKeys, ...restKeys]\n\t) as readonly (keyof T)[];\n\tconst result: Partial<T> = {};\n\n\tfor (const key of keys) {\n\t\tif (hasOwn(object, key)) {\n\t\t\tresult[key] = object[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n","import type { ObjectEntries } from \"./types\";\n\n/**\n * Returns the own enumerable string-keyed entries of an object with preserved\n * key/value pairing.\n *\n * This is a typed wrapper around `Object.entries`.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", active: true } as const;\n *\n * typedEntries(user); // [[\"id\", \"1\"], [\"active\", true]]\n * ```\n */\nexport function typedEntries<T extends object>(object: T): ObjectEntries<T> {\n\treturn Object.entries(object) as unknown as ObjectEntries<T>;\n}\n","import type { EntryTuples, ObjectFromEntries } from \"./types\";\n\n/**\n * Creates an object from entries while preserving the key and value types from\n * the input tuple array.\n *\n * This is a typed wrapper around `Object.fromEntries`.\n *\n * @example\n * ```ts\n * const status = typedFromEntries([\n * [\"id\", \"1\"],\n * [\"active\", true],\n * ] as const);\n *\n * // inferred as: { id: \"1\"; active: true }\n * ```\n */\nexport function typedFromEntries<const T extends EntryTuples>(\n\tentries: T,\n): ObjectFromEntries<T> {\n\treturn Object.fromEntries(entries) as ObjectFromEntries<T>;\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,SAAgB,UAA4B,QAAkC;AAC7E,QAAO,OAAO,KAAK,OAAO;;;;;;;;;;;;;;;;;ACA3B,SAAgB,cAAgC,QAA+B;CAC9E,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,UAAU,OAAO,EAAE;EACpC,MAAM,QAAQ,OAAO;AAErB,MAAI,SAAS,KACZ,QAAO,OAAO;;AAIhB,QAAO;;;;;ACDR,SAAgB,aACf,QACA,WACiD;CACjD,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,UAAU,OAAO,EAAE;EACpC,MAAM,QAAQ,OAAO;AAErB,MAAI,UAAU,OAAO,KAAK,OAAO,CAChC,QAAO,OAAO;;AAIhB,QAAO;;;;;;;;;;;;;;;;;;;;;ACvBR,SAAgB,OACf,QACA,KAC6B;AAC7B,QAAO,OAAO,OAAO,QAAQ,IAAI;;;;;;;;;;;;;;;;ACTlC,SAAgB,SAAY,OAAa;AACxC,QAAO;;;;;;;;;;;;;;;;;ACAR,SAAgB,QAAQ,QAAyB;AAChD,KAAI,OAAO,KAAK,OAAO,CAAC,SAAS,EAChC,QAAO;AAGR,MAAK,MAAM,OAAO,OAAO,sBAAsB,OAAO,CACrD,KAAI,OAAO,UAAU,qBAAqB,KAAK,QAAQ,IAAI,CAC1D,QAAO;AAIT,QAAO;;;;;;;;;;;;;;;;;ACRR,SAAgB,UACf,QACA,QACqB;CACrB,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,UAAU,OAAO,CAClC,QAAO,OAAO,OAAO,OAAO,MAAM,KAAK,OAAO;AAG/C,QAAO;;;;;ACIR,SAAgB,KACf,QACA,gBACA,GAAG,UACU;CACb,MAAM,OACL,MAAM,QAAQ,eAAe,GAC1B,iBACA,CAAC,gBAAgB,GAAG,SAAS;CAEjC,MAAM,cAAc,IAAI,IAAiB,KAA+B;CACxE,MAAMA,SAAqB,EAAE;AAE7B,MAAK,MAAM,OAAO,QAAQ,QAAQ,OAAO,CACxC,KACC,OAAO,UAAU,qBAAqB,KAAK,QAAQ,IAAI,IACvD,CAAC,YAAY,IAAI,IAAI,CAErB,CAAC,OAAa,OAAO,OAAO;AAI9B,QAAO;;;;;ACpBR,SAAgB,KACf,QACA,gBACA,GAAG,UACU;CACb,MAAM,OACL,MAAM,QAAQ,eAAe,GAC1B,iBACA,CAAC,gBAAgB,GAAG,SAAS;CAEjC,MAAMC,SAAqB,EAAE;AAE7B,MAAK,MAAM,OAAO,KACjB,KAAI,OAAO,QAAQ,IAAI,CACtB,QAAO,OAAO,OAAO;AAIvB,QAAO;;;;;;;;;;;;;;;;;;AClCR,SAAgB,aAA+B,QAA6B;AAC3E,QAAO,OAAO,QAAQ,OAAO;;;;;;;;;;;;;;;;;;;;;ACE9B,SAAgB,iBACf,SACuB;AACvB,QAAO,OAAO,YAAY,QAAQ"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["missingKeys: Array<keyof T>","segments: PathSegment[]","toPath","current: unknown","toPath","result: Partial<T>","result: Partial<T>","toPath"],"sources":["../src/core/has-keys.ts","../src/core/require-keys.ts","../src/core/assert-keys.ts","../src/core/typed-keys.ts","../src/core/compact-object.ts","../src/core/filter-values.ts","../src/core/has-own.ts","../src/core/path.ts","../src/core/get.ts","../src/core/has-path.ts","../src/core/identity.ts","../src/core/is-empty.ts","../src/core/is-plain-object.ts","../src/core/map-values.ts","../src/core/omit.ts","../src/core/pick.ts","../src/core/set.ts","../src/core/typed-entries.ts","../src/core/typed-from-entries.ts"],"sourcesContent":["/**\n * Checks whether a plain object has all of the requested own keys.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", role: \"admin\" } as const;\n *\n * hasKeys(user, \"id\", \"role\"); // true\n * hasKeys(user, [\"id\", \"role\"] as const); // true\n * ```\n */\nexport function hasKeys<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tvalue: T,\n\tfirstKey: FirstKey,\n\t...restKeys: RestKeys\n): value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;\nexport function hasKeys<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tvalue: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;\nexport function hasKeys<T extends object>(\n\tvalue: T,\n\tkeys: readonly (keyof T)[],\n): value is T;\nexport function hasKeys<T extends object>(\n\tvalue: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): boolean {\n\tif (value === null || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(value);\n\n\tif (prototype !== Object.prototype && prototype !== null) {\n\t\treturn false;\n\t}\n\n\tconst keys = Array.isArray(firstKeyOrKeys)\n\t\t? firstKeyOrKeys\n\t\t: ([firstKeyOrKeys, ...restKeys] as readonly (keyof T)[]);\n\n\tfor (const key of keys) {\n\t\tif (!Object.hasOwn(value, key)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n","import { hasKeys } from \"./has-keys\";\n\n/**\n * Requires that a plain object has all of the requested own keys.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", role: \"admin\" } as const;\n * const result = requireKeys(user, \"id\", \"role\");\n *\n * result.id; // \"1\"\n * ```\n */\nexport function requireKeys<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tvalue: T,\n\tfirstKey: FirstKey,\n\t...restKeys: RestKeys\n): T & Required<Pick<T, FirstKey | RestKeys[number]>>;\nexport function requireKeys<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tvalue: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): T & Required<Pick<T, FirstKey | RestKeys[number]>>;\nexport function requireKeys<T extends object>(\n\tvalue: T,\n\tkeys: readonly (keyof T)[],\n): T;\nexport function requireKeys<T extends object>(\n\tvalue: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): T {\n\tconst keys = Array.isArray(firstKeyOrKeys)\n\t\t? firstKeyOrKeys\n\t\t: ([firstKeyOrKeys, ...restKeys] as readonly (keyof T)[]);\n\n\tif (hasKeys(value, keys)) {\n\t\treturn value;\n\t}\n\n\tconst missingKeys: Array<keyof T> = [];\n\n\tif (value !== null && typeof value === \"object\") {\n\t\tconst prototype = Object.getPrototypeOf(value);\n\n\t\tif (prototype === Object.prototype || prototype === null) {\n\t\t\tfor (const key of keys) {\n\t\t\t\tif (!Object.hasOwn(value, key)) {\n\t\t\t\t\tmissingKeys.push(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (missingKeys.length === 0) {\n\t\tmissingKeys.push(...keys);\n\t}\n\n\tconst label = missingKeys.length === 1 ? \"key\" : \"keys\";\n\n\tthrow new TypeError(\n\t\t`Missing required ${label}: ${missingKeys.map(String).join(\", \")}`,\n\t);\n}\n","import { requireKeys } from \"./require-keys\";\n\n/**\n * Asserts that a plain object has all of the requested own keys.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", role: \"admin\" } as const;\n *\n * assertKeys(user, \"id\", \"role\");\n * user.id; // \"1\"\n * ```\n */\nexport function assertKeys<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tvalue: T,\n\tfirstKey: FirstKey,\n\t...restKeys: RestKeys\n): asserts value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;\nexport function assertKeys<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tvalue: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): asserts value is T & Required<Pick<T, FirstKey | RestKeys[number]>>;\nexport function assertKeys<T extends object>(\n\tvalue: T,\n\tkeys: readonly (keyof T)[],\n): asserts value is T;\nexport function assertKeys<T extends object>(\n\tvalue: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): void {\n\trequireKeys(value, firstKeyOrKeys as keyof T, ...restKeys);\n}\n","import type { StringKeyOf } from \"./types\";\n\n/**\n * Returns the own enumerable string keys of an object with preserved key types.\n *\n * This is a typed wrapper around `Object.keys`.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\" } as const;\n *\n * typedKeys(user); // [\"id\", \"name\"]\n * ```\n */\nexport function typedKeys<T extends object>(object: T): Array<StringKeyOf<T>> {\n\treturn Object.keys(object) as Array<StringKeyOf<T>>;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { CompactedObject } from \"./types\";\n\n/**\n * Creates a new object with all `null` and `undefined` values removed.\n *\n * Other falsy values such as `0`, `false`, `\"\"`, and `NaN` are preserved.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", nickname: null, active: false } as const;\n *\n * compactObject(user); // { id: \"1\", active: false }\n * ```\n */\nexport function compactObject<T extends object>(object: T): CompactedObject<T> {\n\tconst result = {} as CompactedObject<T>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst value = object[key];\n\n\t\tif (value != null) {\n\t\t\tresult[key] = value as Exclude<T[typeof key], null | undefined>;\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { FilteredValues, ValueGuard, ValuePredicate } from \"./types\";\n\n/**\n * Filters an object's own enumerable string-keyed properties by value.\n *\n * Supports both boolean predicates and type-guard predicates. The result type\n * remains partial because any property may be removed at runtime.\n *\n * @example\n * ```ts\n * const settings = { retries: 3, label: \"\", timeout: null } as const;\n *\n * filterValues(settings, (value) => value !== null);\n * // { retries: 3, label: \"\" }\n * ```\n */\nexport function filterValues<\n\tT extends object,\n\tS extends T[Extract<keyof T, string>],\n>(object: T, predicate: ValueGuard<T, S>): FilteredValues<T, S>;\nexport function filterValues<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): FilteredValues<T, T[Extract<keyof T, string>]>;\nexport function filterValues<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): FilteredValues<T, T[Extract<keyof T, string>]> {\n\tconst result = {} as FilteredValues<T, T[Extract<keyof T, string>]>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst value = object[key];\n\n\t\tif (predicate(value, key, object)) {\n\t\t\tresult[key] = value;\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * Checks whether an object has the given property as its own key.\n *\n * This is a typed wrapper around `Object.hasOwn` that narrows the provided key\n * when the check succeeds.\n *\n * @example\n * ```ts\n * const user = { id: \"1\" };\n * const key: string = \"id\";\n *\n * if (hasOwn(user, key)) {\n * user[key]; // key is narrowed to \"id\"\n * }\n * ```\n */\nexport function hasOwn<T extends object, K extends PropertyKey>(\n\tobject: T,\n\tkey: K,\n): key is Extract<K, keyof T> {\n\treturn Object.hasOwn(object, key);\n}\n","import type { ObjectPath, PathInput, PathSegment } from \"./types\";\n\nconst BRACKET_PATH_SEGMENT_PATTERN =\n\t/[^.[\\]]+|\\[(?:([^\"'[\\]]+)|([\"'])(.*?)\\2)\\]/g;\n\nfunction toPathSegment(value: string): PathSegment {\n\treturn /^\\d+$/.test(value) ? Number(value) : value;\n}\n\n/**\n * Converts dot/bracket notation into a normalized object path array.\n *\n * @example\n * ```ts\n * path(\"profile.addresses[0].city\");\n * // [\"profile\", \"addresses\", 0, \"city\"]\n * ```\n */\nexport function path(input: PathInput): ObjectPath {\n\tif (typeof input !== \"string\") {\n\t\treturn [...input];\n\t}\n\n\tconst source = input;\n\tconst segments: PathSegment[] = [];\n\n\tfor (const match of source.matchAll(BRACKET_PATH_SEGMENT_PATTERN)) {\n\t\tconst [, bareSegment, , quotedSegment] = match;\n\t\tconst segment = quotedSegment ?? bareSegment ?? match[0];\n\n\t\tif (segment !== \"\") {\n\t\t\tsegments.push(toPathSegment(segment));\n\t\t}\n\t}\n\n\treturn segments;\n}\n","import { hasOwn } from \"./has-own\";\nimport { path as toPath } from \"./path\";\nimport type { ObjectPath, PathInput, PathValue } from \"./types\";\n\nfunction hasMissingPathSegment(\n\tvalue: unknown,\n\tsegment: string | number,\n): boolean {\n\treturn (\n\t\tvalue === null ||\n\t\tvalue === undefined ||\n\t\t(typeof value !== \"object\" && typeof value !== \"function\") ||\n\t\t!hasOwn(value, segment)\n\t);\n}\n\n/**\n * Reads a nested own property using a tuple path or dot/bracket notation.\n *\n * @example\n * ```ts\n * const user = { profile: { addresses: [{ city: \"Durban\" }] } } as const;\n *\n * get(user, [\"profile\", \"addresses\", 0, \"city\"]);\n * get(user, \"profile.addresses[0].city\");\n * ```\n */\nexport function get<T, const P extends ObjectPath>(\n\tobject: T,\n\tpath: P,\n): PathValue<T, P> | undefined;\nexport function get<T, const P extends ObjectPath, D>(\n\tobject: T,\n\tpath: P,\n\tdefaultValue: D,\n): Exclude<PathValue<T, P>, undefined> | D;\nexport function get<T>(object: T, path: string): unknown;\nexport function get<T, D>(\n\tobject: T,\n\tpath: string,\n\tdefaultValue: D,\n): D | unknown;\nexport function get<T, D>(\n\tobject: T,\n\tpathInput: PathInput,\n\tdefaultValue?: D,\n): D | unknown {\n\tconst segments = toPath(pathInput);\n\tlet current: unknown = object;\n\n\tfor (const segment of segments) {\n\t\tif (hasMissingPathSegment(current, segment)) {\n\t\t\treturn defaultValue;\n\t\t}\n\n\t\tcurrent = (current as Record<string | number, unknown>)[segment];\n\t}\n\n\treturn current;\n}\n","import { hasOwn } from \"./has-own\";\nimport { path as toPath } from \"./path\";\nimport type { PathInput } from \"./types\";\n\n/**\n * Checks whether a nested own-property path exists.\n *\n * A resolved `undefined` value still counts as existing as long as every\n * segment is present as an own property.\n */\nexport function hasPath(object: unknown, pathInput: PathInput): boolean {\n\tlet current = object;\n\n\tfor (const segment of toPath(pathInput)) {\n\t\tif (\n\t\t\tcurrent === null ||\n\t\t\tcurrent === undefined ||\n\t\t\t(typeof current !== \"object\" && typeof current !== \"function\") ||\n\t\t\t!hasOwn(current, segment)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tcurrent = (current as Record<string | number, unknown>)[segment];\n\t}\n\n\treturn true;\n}\n","/**\n * Returns the given value unchanged.\n *\n * Useful as a default callback, a type-inference anchor, or a no-op\n * placeholder where a transform function is expected.\n *\n * @example\n * ```ts\n * identity(\"umsizi\"); // \"umsizi\"\n * ```\n */\nexport function identity<T>(value: T): T {\n\treturn value;\n}\n","/**\n * Returns `true` when an object has no own enumerable properties.\n *\n * Both string keys and symbol keys are considered. Non-enumerable properties\n * are ignored.\n *\n * @example\n * ```ts\n * isEmpty({}); // true\n * isEmpty({ id: \"1\" }); // false\n * ```\n */\nexport function isEmpty(object: object): boolean {\n\tif (Object.keys(object).length > 0) {\n\t\treturn false;\n\t}\n\n\tfor (const key of Object.getOwnPropertySymbols(object)) {\n\t\tif (Object.prototype.propertyIsEnumerable.call(object, key)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n","/**\n * Checks whether a value is a plain object with a prototype of\n * `Object.prototype` or `null`.\n *\n * Arrays, functions, boxed primitives, dates, maps, sets, and class instances\n * all return `false`.\n *\n * @example\n * ```ts\n * const payload: unknown = { id: \"1\" };\n *\n * if (isPlainObject(payload)) {\n * \tpayload.id;\n * }\n * ```\n */\nexport function isPlainObject(\n\tvalue: unknown,\n): value is Record<PropertyKey, unknown> {\n\tif (value === null || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\n\tconst prototype = Object.getPrototypeOf(value);\n\n\treturn prototype === Object.prototype || prototype === null;\n}\n","import { typedKeys } from \"./typed-keys\";\nimport type { MappedValues, ValueMapper } from \"./types\";\n\n/**\n * Maps the values of an object's own enumerable string-keyed properties while\n * preserving the original enumerable string-key set.\n *\n * @example\n * ```ts\n * const counts = { draft: 1, published: 2 };\n *\n * mapValues(counts, (value) => value * 2);\n * // { draft: 2, published: 4 }\n * ```\n */\nexport function mapValues<T extends object, R>(\n\tobject: T,\n\tmapper: ValueMapper<T, R>,\n): MappedValues<T, R> {\n\tconst result = {} as MappedValues<T, R>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tresult[key] = mapper(object[key], key, object);\n\t}\n\n\treturn result;\n}\n","/**\n * Creates a new object excluding the selected own enumerable properties.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\", role: \"admin\" } as const;\n *\n * omit(user, \"id\", \"name\"); // { role: \"admin\" }\n * omit(user, [\"role\"] as const); // { id: \"1\", name: \"Umsizi\" }\n * ```\n */\nexport function omit<T extends object, const Keys extends readonly (keyof T)[]>(\n\tobject: T,\n\t...keys: Keys\n): Omit<T, Keys[number]>;\nexport function omit<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tobject: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): Omit<T, FirstKey | RestKeys[number]>;\nexport function omit<T extends object>(\n\tobject: T,\n\tkeys: readonly (keyof T)[],\n): Partial<T>;\nexport function omit<T extends object>(\n\tobject: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): Partial<T> {\n\tconst keys = (\n\t\tArray.isArray(firstKeyOrKeys)\n\t\t\t? firstKeyOrKeys\n\t\t\t: [firstKeyOrKeys, ...restKeys]\n\t) as readonly (keyof T)[];\n\tconst omittedKeys = new Set<PropertyKey>(keys as readonly PropertyKey[]);\n\tconst result: Partial<T> = {};\n\n\tfor (const key of Reflect.ownKeys(object) as (keyof T)[]) {\n\t\tif (\n\t\t\tObject.prototype.propertyIsEnumerable.call(object, key) &&\n\t\t\t!omittedKeys.has(key)\n\t\t) {\n\t\t\t(result as T)[key] = object[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { hasOwn } from \"./has-own\";\n\n/**\n * Creates a new object containing only the selected own properties.\n *\n * Prefer the rest-key form for the strongest autocomplete and inference.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", name: \"Umsizi\", role: \"admin\" } as const;\n *\n * pick(user, \"name\"); // { name: \"Umsizi\" }\n * pick(user, [\"id\", \"role\"] as const); // { id: \"1\", role: \"admin\" }\n * ```\n */\nexport function pick<T extends object, const Keys extends readonly (keyof T)[]>(\n\tobject: T,\n\t...keys: Keys\n): Pick<T, Keys[number]>;\nexport function pick<\n\tT extends object,\n\tconst FirstKey extends keyof T,\n\tconst RestKeys extends readonly (keyof T)[],\n>(\n\tobject: T,\n\tkeys: readonly [FirstKey, ...RestKeys],\n): Pick<T, FirstKey | RestKeys[number]>;\nexport function pick<T extends object>(\n\tobject: T,\n\tkeys: readonly (keyof T)[],\n): Partial<T>;\nexport function pick<T extends object>(\n\tobject: T,\n\tfirstKeyOrKeys: keyof T | readonly (keyof T)[],\n\t...restKeys: readonly (keyof T)[]\n): Partial<T> {\n\tconst keys = (\n\t\tArray.isArray(firstKeyOrKeys)\n\t\t\t? firstKeyOrKeys\n\t\t\t: [firstKeyOrKeys, ...restKeys]\n\t) as readonly (keyof T)[];\n\tconst result: Partial<T> = {};\n\n\tfor (const key of keys) {\n\t\tif (hasOwn(object, key)) {\n\t\t\tresult[key] = object[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n","import { path as toPath } from \"./path\";\nimport type { PathInput, PathSegment } from \"./types\";\n\nfunction isContainer(value: unknown): value is object {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction createContainer(\n\tnextSegment: PathSegment | undefined,\n): unknown[] | Record<string, unknown> {\n\treturn typeof nextSegment === \"number\" ? [] : {};\n}\n\nfunction cloneContainer(value: unknown, nextSegment: PathSegment | undefined) {\n\tif (Array.isArray(value)) {\n\t\treturn [...value];\n\t}\n\n\tif (isContainer(value)) {\n\t\treturn Object.assign(\n\t\t\tObject.create(Object.getPrototypeOf(value)),\n\t\t\tvalue,\n\t\t) as Record<string | number, unknown>;\n\t}\n\n\treturn createContainer(nextSegment);\n}\n\nfunction setAtPath(\n\tcurrent: unknown,\n\tsegments: readonly PathSegment[],\n\tvalue: unknown,\n): unknown {\n\tconst [segment, ...rest] = segments as readonly [\n\t\tPathSegment,\n\t\t...PathSegment[],\n\t];\n\n\tconst clone = cloneContainer(current, segment) as Record<\n\t\tPropertyKey,\n\t\tunknown\n\t>;\n\tconst existingValue =\n\t\tisContainer(current) || Array.isArray(current)\n\t\t\t? (current as Record<string | number, unknown>)[segment]\n\t\t\t: undefined;\n\n\tclone[segment] =\n\t\trest.length === 0 ? value : setAtPath(existingValue, rest, value);\n\n\treturn clone;\n}\n\n/**\n * Returns a new object with the nested path set to the given value.\n *\n * Missing containers are created automatically. Only the updated path is\n * cloned; untouched branches retain their existing references.\n */\nexport function set<T extends object>(\n\tobject: T,\n\tpathInput: PathInput,\n\tvalue: unknown,\n): T {\n\tconst segments = toPath(pathInput);\n\n\tif (segments.length === 0) {\n\t\treturn object;\n\t}\n\n\treturn setAtPath(object, segments, value) as T;\n}\n","import type { ObjectEntries } from \"./types\";\n\n/**\n * Returns the own enumerable string-keyed entries of an object with preserved\n * key/value pairing.\n *\n * This is a typed wrapper around `Object.entries`.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", active: true } as const;\n *\n * typedEntries(user); // [[\"id\", \"1\"], [\"active\", true]]\n * ```\n */\nexport function typedEntries<T extends object>(object: T): ObjectEntries<T> {\n\treturn Object.entries(object) as unknown as ObjectEntries<T>;\n}\n","import type { EntryTuples, ObjectFromEntries } from \"./types\";\n\n/**\n * Creates an object from entries while preserving the key and value types from\n * the input tuple array.\n *\n * This is a typed wrapper around `Object.fromEntries`.\n *\n * @example\n * ```ts\n * const status = typedFromEntries([\n * [\"id\", \"1\"],\n * [\"active\", true],\n * ] as const);\n *\n * // inferred as: { id: \"1\"; active: true }\n * ```\n */\nexport function typedFromEntries<const T extends EntryTuples>(\n\tentries: T,\n): ObjectFromEntries<T> {\n\treturn Object.fromEntries(entries) as ObjectFromEntries<T>;\n}\n"],"mappings":"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"}
|
package/dist/next.d.ts
CHANGED
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
* - Strips a trailing slash (except for the root path).
|
|
8
8
|
* - An empty string normalizes to `"/"`.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* A query string or fragment, if present, is left untouched — only the
|
|
11
|
+
* pathname segment preceding the first `?` or `#` is normalized.
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```ts
|
|
15
15
|
* normalizePathname("dashboard"); // "/dashboard"
|
|
16
16
|
* normalizePathname("//dashboard///settings/"); // "/dashboard/settings"
|
|
17
17
|
* normalizePathname(""); // "/"
|
|
18
|
+
* normalizePathname("dashboard?redirect=//evil.com"); // "/dashboard?redirect=//evil.com"
|
|
18
19
|
* ```
|
|
19
20
|
*/
|
|
20
21
|
declare function normalizePathname(pathname: string): string;
|
package/dist/next.js
CHANGED
|
@@ -7,21 +7,25 @@
|
|
|
7
7
|
* - Strips a trailing slash (except for the root path).
|
|
8
8
|
* - An empty string normalizes to `"/"`.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* A query string or fragment, if present, is left untouched — only the
|
|
11
|
+
* pathname segment preceding the first `?` or `#` is normalized.
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```ts
|
|
15
15
|
* normalizePathname("dashboard"); // "/dashboard"
|
|
16
16
|
* normalizePathname("//dashboard///settings/"); // "/dashboard/settings"
|
|
17
17
|
* normalizePathname(""); // "/"
|
|
18
|
+
* normalizePathname("dashboard?redirect=//evil.com"); // "/dashboard?redirect=//evil.com"
|
|
18
19
|
* ```
|
|
19
20
|
*/
|
|
20
21
|
function normalizePathname(pathname) {
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const suffixIndex = pathname.search(/[?#]/);
|
|
23
|
+
const path = suffixIndex === -1 ? pathname : pathname.slice(0, suffixIndex);
|
|
24
|
+
const suffix = suffixIndex === -1 ? "" : pathname.slice(suffixIndex);
|
|
25
|
+
if (path === "") return `/${suffix}`;
|
|
26
|
+
const normalized = path.replace(/\/{2,}/g, "/").replace(/\/$/, "");
|
|
27
|
+
if (normalized === "") return `/${suffix}`;
|
|
28
|
+
return (normalized.startsWith("/") ? normalized : `/${normalized}`) + suffix;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
//#endregion
|
package/dist/next.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next.js","names":[],"sources":["../src/next/normalize-pathname.ts"],"sourcesContent":["/**\n * Normalizes a path-like string for routing/comparison purposes.\n *\n * - Ensures a leading slash.\n * - Collapses consecutive slashes into one.\n * - Strips a trailing slash (except for the root path).\n * - An empty string normalizes to `\"/\"`.\n *\n *
|
|
1
|
+
{"version":3,"file":"next.js","names":[],"sources":["../src/next/normalize-pathname.ts"],"sourcesContent":["/**\n * Normalizes a path-like string for routing/comparison purposes.\n *\n * - Ensures a leading slash.\n * - Collapses consecutive slashes into one.\n * - Strips a trailing slash (except for the root path).\n * - An empty string normalizes to `\"/\"`.\n *\n * A query string or fragment, if present, is left untouched — only the\n * pathname segment preceding the first `?` or `#` is normalized.\n *\n * @example\n * ```ts\n * normalizePathname(\"dashboard\"); // \"/dashboard\"\n * normalizePathname(\"//dashboard///settings/\"); // \"/dashboard/settings\"\n * normalizePathname(\"\"); // \"/\"\n * normalizePathname(\"dashboard?redirect=//evil.com\"); // \"/dashboard?redirect=//evil.com\"\n * ```\n */\nexport function normalizePathname(pathname: string): string {\n\tconst suffixIndex = pathname.search(/[?#]/);\n\tconst path = suffixIndex === -1 ? pathname : pathname.slice(0, suffixIndex);\n\tconst suffix = suffixIndex === -1 ? \"\" : pathname.slice(suffixIndex);\n\n\tif (path === \"\") {\n\t\treturn `/${suffix}`;\n\t}\n\n\tconst normalized = path.replace(/\\/{2,}/g, \"/\").replace(/\\/$/, \"\");\n\n\tif (normalized === \"\") {\n\t\treturn `/${suffix}`;\n\t}\n\n\treturn (normalized.startsWith(\"/\") ? normalized : `/${normalized}`) + suffix;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,kBAAkB,UAA0B;CAC3D,MAAM,cAAc,SAAS,OAAO,OAAO;CAC3C,MAAM,OAAO,gBAAgB,KAAK,WAAW,SAAS,MAAM,GAAG,YAAY;CAC3E,MAAM,SAAS,gBAAgB,KAAK,KAAK,SAAS,MAAM,YAAY;AAEpE,KAAI,SAAS,GACZ,QAAO,IAAI;CAGZ,MAAM,aAAa,KAAK,QAAQ,WAAW,IAAI,CAAC,QAAQ,OAAO,GAAG;AAElE,KAAI,eAAe,GAClB,QAAO,IAAI;AAGZ,SAAQ,WAAW,WAAW,IAAI,GAAG,aAAa,IAAI,gBAAgB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "umsizi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A zero-dependency TypeScript utility library.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jack-WebDev",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
{
|
|
73
73
|
"name": "umsizi (core)",
|
|
74
74
|
"path": "dist/index.js",
|
|
75
|
-
"limit": "
|
|
75
|
+
"limit": "1 KB"
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
"name": "umsizi/react",
|