umsizi 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -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
package/dist/index.d.ts CHANGED
@@ -18,17 +18,31 @@ declare function assertKeys<T extends object>(value: T, keys: readonly (keyof T)
18
18
  //#endregion
19
19
  //#region src/core/types.d.ts
20
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;
21
24
  type ObjectEntry<T extends object> = { [K in StringKeyOf<T>]: readonly [K, T[K]] }[StringKeyOf<T>];
22
25
  type ObjectEntries<T extends object> = Array<ObjectEntry<T>>;
23
26
  type EntryTuple = readonly [PropertyKey, unknown];
24
27
  type EntryTuples = ReadonlyArray<EntryTuple>;
25
28
  type ObjectFromEntries<T extends EntryTuples> = { [K in T[number] as K[0]]: K[1] };
26
29
  type ValueMapper<T extends object, R> = (value: T[StringKeyOf<T>], key: StringKeyOf<T>, object: T) => R;
30
+ type KeyMapper<T extends object, R extends string> = (key: StringKeyOf<T>, value: T[StringKeyOf<T>], object: T) => R;
31
+ type KeyPredicate<T extends object> = (key: StringKeyOf<T>, value: T[StringKeyOf<T>], object: T) => boolean;
32
+ type KeyGuard<T extends object, S extends StringKeyOf<T>> = (key: StringKeyOf<T>, value: T[StringKeyOf<T>], object: T) => key is S;
27
33
  type ValuePredicate<T extends object> = (value: T[StringKeyOf<T>], key: StringKeyOf<T>, object: T) => boolean;
28
34
  type ValueGuard<T extends object, S extends T[StringKeyOf<T>]> = (value: T[StringKeyOf<T>], key: StringKeyOf<T>, object: T) => value is S;
29
35
  type MappedValues<T extends object, R> = { [K in StringKeyOf<T>]: R };
36
+ type MappedKeys<T extends object, R extends string> = Record<R, T[StringKeyOf<T>]>;
37
+ type RenamedKeys<T extends object, M extends Partial<Record<StringKeyOf<T>, string>>> = { [K in StringKeyOf<T> as K extends keyof M ? M[K] extends string ? M[K] : K : K]: T[K] };
30
38
  type FilteredValues<T extends object, S extends T[StringKeyOf<T>]> = Partial<{ [K in StringKeyOf<T>]: Extract<T[K], S> }>;
39
+ type FilteredKeys<T extends object, S extends StringKeyOf<T>> = Partial<Pick<T, S>>;
40
+ type PartitionedValues<T extends object, S extends T[StringKeyOf<T>]> = readonly [FilteredValues<T, S>, Partial<{ [K in StringKeyOf<T>]: Exclude<T[K], S> }>];
41
+ type PartitionedObject<T extends object> = readonly [Partial<{ [K in StringKeyOf<T>]: T[K] }>, Partial<{ [K in StringKeyOf<T>]: T[K] }>];
31
42
  type CompactedObject<T extends object> = Partial<{ [K in StringKeyOf<T>]: Exclude<T[K], null | undefined> }>;
43
+ type InvertedObject<T extends Record<string, PropertyKey>> = { [K in StringKeyOf<T> as T[K]]: K };
44
+ 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;
45
+ 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;
32
46
  //#endregion
33
47
  //#region src/core/compact-object.d.ts
34
48
  /**
@@ -45,6 +59,24 @@ type CompactedObject<T extends object> = Partial<{ [K in StringKeyOf<T>]: Exclud
45
59
  */
46
60
  declare function compactObject<T extends object>(object: T): CompactedObject<T>;
47
61
  //#endregion
62
+ //#region src/core/filter-keys.d.ts
63
+ /**
64
+ * Filters an object's own enumerable string-keyed properties by key.
65
+ *
66
+ * Supports both boolean predicates and key type guards. The result remains
67
+ * partial because any property may be removed at runtime.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * const metrics = { total: 5, temp_cache: 2, temp_jobs: 1 } as const;
72
+ *
73
+ * filterKeys(metrics, (key) => key.startsWith("temp_"));
74
+ * // { temp_cache: 2, temp_jobs: 1 }
75
+ * ```
76
+ */
77
+ declare function filterKeys<T extends object, S extends Extract<keyof T, string>>(object: T, predicate: KeyGuard<T, S>): FilteredKeys<T, S>;
78
+ declare function filterKeys<T extends object>(object: T, predicate: KeyPredicate<T>): FilteredKeys<T, Extract<keyof T, string>>;
79
+ //#endregion
48
80
  //#region src/core/filter-values.d.ts
49
81
  /**
50
82
  * Filters an object's own enumerable string-keyed properties by value.
@@ -63,6 +95,23 @@ declare function compactObject<T extends object>(object: T): CompactedObject<T>;
63
95
  declare function filterValues<T extends object, S extends T[Extract<keyof T, string>]>(object: T, predicate: ValueGuard<T, S>): FilteredValues<T, S>;
64
96
  declare function filterValues<T extends object>(object: T, predicate: ValuePredicate<T>): FilteredValues<T, T[Extract<keyof T, string>]>;
65
97
  //#endregion
98
+ //#region src/core/get.d.ts
99
+ /**
100
+ * Reads a nested own property using a tuple path or dot/bracket notation.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const user = { profile: { addresses: [{ city: "Durban" }] } } as const;
105
+ *
106
+ * get(user, ["profile", "addresses", 0, "city"]);
107
+ * get(user, "profile.addresses[0].city");
108
+ * ```
109
+ */
110
+ declare function get<T, const P extends ObjectPath>(object: T, path: P): PathValue<T, P> | undefined;
111
+ declare function get<T, const P extends ObjectPath, D>(object: T, path: P, defaultValue: D): Exclude<PathValue<T, P>, undefined> | D;
112
+ declare function get<T>(object: T, path: string): unknown;
113
+ declare function get<T, D>(object: T, path: string, defaultValue: D): D | unknown;
114
+ //#endregion
66
115
  //#region src/core/has-keys.d.ts
67
116
  /**
68
117
  * Checks whether a plain object has all of the requested own keys.
@@ -100,6 +149,15 @@ declare function hasKeys<T extends object>(value: T, keys: readonly (keyof T)[])
100
149
  */
101
150
  declare function hasOwn<T extends object, K$1 extends PropertyKey>(object: T, key: K$1): key is Extract<K$1, keyof T>;
102
151
  //#endregion
152
+ //#region src/core/has-path.d.ts
153
+ /**
154
+ * Checks whether a nested own-property path exists.
155
+ *
156
+ * A resolved `undefined` value still counts as existing as long as every
157
+ * segment is present as an own property.
158
+ */
159
+ declare function hasPath(object: unknown, pathInput: PathInput): boolean;
160
+ //#endregion
103
161
  //#region src/core/identity.d.ts
104
162
  /**
105
163
  * Returns the given value unchanged.
@@ -114,6 +172,23 @@ declare function hasOwn<T extends object, K$1 extends PropertyKey>(object: T, ke
114
172
  */
115
173
  declare function identity<T>(value: T): T;
116
174
  //#endregion
175
+ //#region src/core/invert-object.d.ts
176
+ /**
177
+ * Inverts an object's own enumerable string-keyed properties.
178
+ *
179
+ * Source values must be valid property keys. When multiple source keys share
180
+ * the same value, the later assignment wins.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * const roles = { admin: "A", member: "M" } as const;
185
+ *
186
+ * invertObject(roles);
187
+ * // { A: "admin", M: "member" }
188
+ * ```
189
+ */
190
+ declare function invertObject<T extends Record<string, PropertyKey>>(object: T): InvertedObject<T>;
191
+ //#endregion
117
192
  //#region src/core/is-empty.d.ts
118
193
  /**
119
194
  * Returns `true` when an object has no own enumerable properties.
@@ -148,6 +223,23 @@ declare function isEmpty(object: object): boolean;
148
223
  */
149
224
  declare function isPlainObject(value: unknown): value is Record<PropertyKey, unknown>;
150
225
  //#endregion
226
+ //#region src/core/map-keys.d.ts
227
+ /**
228
+ * Maps an object's own enumerable string keys to new string keys.
229
+ *
230
+ * When multiple source keys map to the same target key, the later assignment
231
+ * wins.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * const user = { id: "1", active: true } as const;
236
+ *
237
+ * mapKeys(user, (key) => `user_${key}`);
238
+ * // { user_id: "1", user_active: true }
239
+ * ```
240
+ */
241
+ declare function mapKeys<T extends object, R extends string>(object: T, mapper: KeyMapper<T, R>): MappedKeys<T, R>;
242
+ //#endregion
151
243
  //#region src/core/map-values.d.ts
152
244
  /**
153
245
  * Maps the values of an object's own enumerable string-keyed properties while
@@ -181,6 +273,36 @@ declare function omit<T extends object, const Keys extends readonly (keyof T)[]>
181
273
  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]>;
182
274
  declare function omit<T extends object>(object: T, keys: readonly (keyof T)[]): Partial<T>;
183
275
  //#endregion
276
+ //#region src/core/partition-object.d.ts
277
+ /**
278
+ * Partitions an object's own enumerable string-keyed properties into matching
279
+ * and non-matching objects.
280
+ *
281
+ * Supports both boolean predicates and type-guard predicates.
282
+ *
283
+ * @example
284
+ * ```ts
285
+ * const settings = { retries: 3, label: "ok", timeout: null } as const;
286
+ *
287
+ * partitionObject(settings, (value) => value !== null);
288
+ * // [{ retries: 3, label: "ok" }, { timeout: null }]
289
+ * ```
290
+ */
291
+ declare function partitionObject<T extends object, S extends T[Extract<keyof T, string>]>(object: T, predicate: ValueGuard<T, S>): PartitionedValues<T, S>;
292
+ declare function partitionObject<T extends object>(object: T, predicate: ValuePredicate<T>): PartitionedObject<T>;
293
+ //#endregion
294
+ //#region src/core/path.d.ts
295
+ /**
296
+ * Converts dot/bracket notation into a normalized object path array.
297
+ *
298
+ * @example
299
+ * ```ts
300
+ * path("profile.addresses[0].city");
301
+ * // ["profile", "addresses", 0, "city"]
302
+ * ```
303
+ */
304
+ declare function path(input: PathInput): ObjectPath;
305
+ //#endregion
184
306
  //#region src/core/pick.d.ts
185
307
  /**
186
308
  * Creates a new object containing only the selected own properties.
@@ -199,6 +321,23 @@ declare function pick<T extends object, const Keys extends readonly (keyof T)[]>
199
321
  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]>;
200
322
  declare function pick<T extends object>(object: T, keys: readonly (keyof T)[]): Partial<T>;
201
323
  //#endregion
324
+ //#region src/core/rename-keys.d.ts
325
+ /**
326
+ * Renames selected own enumerable string-keyed properties using a key map.
327
+ *
328
+ * Unmapped keys are copied through unchanged. When multiple source keys resolve
329
+ * to the same target key, the later assignment wins.
330
+ *
331
+ * @example
332
+ * ```ts
333
+ * const user = { id: "1", givenName: "Umsizi" } as const;
334
+ *
335
+ * renameKeys(user, { givenName: "name" });
336
+ * // { id: "1", name: "Umsizi" }
337
+ * ```
338
+ */
339
+ declare function renameKeys<T extends object, const M extends Partial<Record<Extract<keyof T, string>, string>>>(object: T, names: M): RenamedKeys<T, M>;
340
+ //#endregion
202
341
  //#region src/core/require-keys.d.ts
203
342
  /**
204
343
  * Requires that a plain object has all of the requested own keys.
@@ -217,6 +356,15 @@ declare function requireKeys<T extends object, const FirstKey extends keyof T, c
217
356
  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]>>;
218
357
  declare function requireKeys<T extends object>(value: T, keys: readonly (keyof T)[]): T;
219
358
  //#endregion
359
+ //#region src/core/set.d.ts
360
+ /**
361
+ * Returns a new object with the nested path set to the given value.
362
+ *
363
+ * Missing containers are created automatically. Only the updated path is
364
+ * cloned; untouched branches retain their existing references.
365
+ */
366
+ declare function set<T extends object>(object: T, pathInput: PathInput, value: unknown): T;
367
+ //#endregion
220
368
  //#region src/core/typed-entries.d.ts
221
369
  /**
222
370
  * Returns the own enumerable string-keyed entries of an object with preserved
@@ -267,5 +415,5 @@ declare function typedFromEntries<const T extends EntryTuples>(entries: T): Obje
267
415
  */
268
416
  declare function typedKeys<T extends object>(object: T): Array<StringKeyOf<T>>;
269
417
  //#endregion
270
- export { assertKeys, compactObject, filterValues, hasKeys, hasOwn, identity, isEmpty, isPlainObject, isPlainObject as isRecord, mapValues, omit, pick, requireKeys, typedEntries, typedFromEntries, typedKeys };
418
+ export { assertKeys, compactObject, filterKeys, filterValues, get, hasKeys, hasOwn, hasPath, identity, invertObject, isEmpty, isPlainObject, isPlainObject as isRecord, mapKeys, mapValues, omit, partitionObject, path, pick, renameKeys, requireKeys, set, typedEntries, typedFromEntries, typedKeys };
271
419
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -21,7 +21,8 @@ function requireKeys(value, firstKeyOrKeys, ...restKeys) {
21
21
  }
22
22
  }
23
23
  if (missingKeys.length === 0) missingKeys.push(...keys);
24
- throw new TypeError(`M:${missingKeys.map(String).join()}`);
24
+ const label = missingKeys.length === 1 ? "key" : "keys";
25
+ throw new TypeError(`Missing required ${label}: ${missingKeys.map(String).join(", ")}`);
25
26
  }
26
27
 
27
28
  //#endregion
@@ -71,6 +72,14 @@ function compactObject(object) {
71
72
  return result;
72
73
  }
73
74
 
75
+ //#endregion
76
+ //#region src/core/filter-keys.ts
77
+ function filterKeys(object, predicate) {
78
+ const result = {};
79
+ for (const key of typedKeys(object)) if (predicate(key, object[key], object)) result[key] = object[key];
80
+ return result;
81
+ }
82
+
74
83
  //#endregion
75
84
  //#region src/core/filter-values.ts
76
85
  function filterValues(object, predicate) {
@@ -104,6 +113,65 @@ function hasOwn(object, key) {
104
113
  return Object.hasOwn(object, key);
105
114
  }
106
115
 
116
+ //#endregion
117
+ //#region src/core/path.ts
118
+ const BRACKET_PATH_SEGMENT_PATTERN = /[^.[\]]+|\[(?:([^"'[\]]+)|(["'])(.*?)\2)\]/g;
119
+ function toPathSegment(value) {
120
+ return /^\d+$/.test(value) ? Number(value) : value;
121
+ }
122
+ /**
123
+ * Converts dot/bracket notation into a normalized object path array.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * path("profile.addresses[0].city");
128
+ * // ["profile", "addresses", 0, "city"]
129
+ * ```
130
+ */
131
+ function path(input) {
132
+ if (typeof input !== "string") return [...input];
133
+ const source = input;
134
+ const segments = [];
135
+ for (const match of source.matchAll(BRACKET_PATH_SEGMENT_PATTERN)) {
136
+ const [, bareSegment, , quotedSegment] = match;
137
+ const segment = quotedSegment ?? bareSegment ?? match[0];
138
+ if (segment !== "") segments.push(toPathSegment(segment));
139
+ }
140
+ return segments;
141
+ }
142
+
143
+ //#endregion
144
+ //#region src/core/get.ts
145
+ function hasMissingPathSegment(value, segment) {
146
+ return value === null || value === void 0 || typeof value !== "object" && typeof value !== "function" || !hasOwn(value, segment);
147
+ }
148
+ function get(object, pathInput, defaultValue) {
149
+ const segments = path(pathInput);
150
+ let current = object;
151
+ for (const segment of segments) {
152
+ if (hasMissingPathSegment(current, segment)) return defaultValue;
153
+ current = current[segment];
154
+ }
155
+ return current;
156
+ }
157
+
158
+ //#endregion
159
+ //#region src/core/has-path.ts
160
+ /**
161
+ * Checks whether a nested own-property path exists.
162
+ *
163
+ * A resolved `undefined` value still counts as existing as long as every
164
+ * segment is present as an own property.
165
+ */
166
+ function hasPath(object, pathInput) {
167
+ let current = object;
168
+ for (const segment of path(pathInput)) {
169
+ if (current === null || current === void 0 || typeof current !== "object" && typeof current !== "function" || !hasOwn(current, segment)) return false;
170
+ current = current[segment];
171
+ }
172
+ return true;
173
+ }
174
+
107
175
  //#endregion
108
176
  //#region src/core/identity.ts
109
177
  /**
@@ -121,6 +189,31 @@ function identity(value) {
121
189
  return value;
122
190
  }
123
191
 
192
+ //#endregion
193
+ //#region src/core/invert-object.ts
194
+ /**
195
+ * Inverts an object's own enumerable string-keyed properties.
196
+ *
197
+ * Source values must be valid property keys. When multiple source keys share
198
+ * the same value, the later assignment wins.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * const roles = { admin: "A", member: "M" } as const;
203
+ *
204
+ * invertObject(roles);
205
+ * // { A: "admin", M: "member" }
206
+ * ```
207
+ */
208
+ function invertObject(object) {
209
+ const result = {};
210
+ for (const key of typedKeys(object)) {
211
+ const value = object[key];
212
+ result[value] = key;
213
+ }
214
+ return result;
215
+ }
216
+
124
217
  //#endregion
125
218
  //#region src/core/is-empty.ts
126
219
  /**
@@ -165,6 +258,31 @@ function isPlainObject(value) {
165
258
  return prototype === Object.prototype || prototype === null;
166
259
  }
167
260
 
261
+ //#endregion
262
+ //#region src/core/map-keys.ts
263
+ /**
264
+ * Maps an object's own enumerable string keys to new string keys.
265
+ *
266
+ * When multiple source keys map to the same target key, the later assignment
267
+ * wins.
268
+ *
269
+ * @example
270
+ * ```ts
271
+ * const user = { id: "1", active: true } as const;
272
+ *
273
+ * mapKeys(user, (key) => `user_${key}`);
274
+ * // { user_id: "1", user_active: true }
275
+ * ```
276
+ */
277
+ function mapKeys(object, mapper) {
278
+ const result = {};
279
+ for (const key of typedKeys(object)) {
280
+ const mappedKey = mapper(key, object[key], object);
281
+ result[mappedKey] = object[key];
282
+ }
283
+ return result;
284
+ }
285
+
168
286
  //#endregion
169
287
  //#region src/core/map-values.ts
170
288
  /**
@@ -195,6 +313,22 @@ function omit(object, firstKeyOrKeys, ...restKeys) {
195
313
  return result;
196
314
  }
197
315
 
316
+ //#endregion
317
+ //#region src/core/partition-object.ts
318
+ function partitionObject(object, predicate) {
319
+ const matching = {};
320
+ const rest = {};
321
+ for (const key of typedKeys(object)) {
322
+ const value = object[key];
323
+ if (predicate(value, key, object)) {
324
+ matching[key] = value;
325
+ continue;
326
+ }
327
+ rest[key] = value;
328
+ }
329
+ return [matching, rest];
330
+ }
331
+
198
332
  //#endregion
199
333
  //#region src/core/pick.ts
200
334
  function pick(object, firstKeyOrKeys, ...restKeys) {
@@ -204,6 +338,63 @@ function pick(object, firstKeyOrKeys, ...restKeys) {
204
338
  return result;
205
339
  }
206
340
 
341
+ //#endregion
342
+ //#region src/core/rename-keys.ts
343
+ /**
344
+ * Renames selected own enumerable string-keyed properties using a key map.
345
+ *
346
+ * Unmapped keys are copied through unchanged. When multiple source keys resolve
347
+ * to the same target key, the later assignment wins.
348
+ *
349
+ * @example
350
+ * ```ts
351
+ * const user = { id: "1", givenName: "Umsizi" } as const;
352
+ *
353
+ * renameKeys(user, { givenName: "name" });
354
+ * // { id: "1", name: "Umsizi" }
355
+ * ```
356
+ */
357
+ function renameKeys(object, names) {
358
+ const result = {};
359
+ for (const key of typedKeys(object)) {
360
+ const renamedKey = hasOwn(names, key) ? names[key] : key;
361
+ result[renamedKey] = object[key];
362
+ }
363
+ return result;
364
+ }
365
+
366
+ //#endregion
367
+ //#region src/core/set.ts
368
+ function isContainer(value) {
369
+ return typeof value === "object" && value !== null;
370
+ }
371
+ function createContainer(nextSegment) {
372
+ return typeof nextSegment === "number" ? [] : {};
373
+ }
374
+ function cloneContainer(value, nextSegment) {
375
+ if (Array.isArray(value)) return [...value];
376
+ if (isContainer(value)) return Object.assign(Object.create(Object.getPrototypeOf(value)), value);
377
+ return createContainer(nextSegment);
378
+ }
379
+ function setAtPath(current, segments, value) {
380
+ const [segment, ...rest] = segments;
381
+ const clone = cloneContainer(current, segment);
382
+ const existingValue = isContainer(current) || Array.isArray(current) ? current[segment] : void 0;
383
+ clone[segment] = rest.length === 0 ? value : setAtPath(existingValue, rest, value);
384
+ return clone;
385
+ }
386
+ /**
387
+ * Returns a new object with the nested path set to the given value.
388
+ *
389
+ * Missing containers are created automatically. Only the updated path is
390
+ * cloned; untouched branches retain their existing references.
391
+ */
392
+ function set(object, pathInput, value) {
393
+ const segments = path(pathInput);
394
+ if (segments.length === 0) return object;
395
+ return setAtPath(object, segments, value);
396
+ }
397
+
207
398
  //#endregion
208
399
  //#region src/core/typed-entries.ts
209
400
  /**
@@ -246,5 +437,5 @@ function typedFromEntries(entries) {
246
437
  }
247
438
 
248
439
  //#endregion
249
- export { assertKeys, compactObject, filterValues, hasKeys, hasOwn, identity, isEmpty, isPlainObject, isPlainObject as isRecord, mapValues, omit, pick, requireKeys, typedEntries, typedFromEntries, typedKeys };
440
+ export { assertKeys, compactObject, filterKeys, filterValues, get, hasKeys, hasOwn, hasPath, identity, invertObject, isEmpty, isPlainObject, isPlainObject as isRecord, mapKeys, mapValues, omit, partitionObject, path, pick, renameKeys, requireKeys, set, typedEntries, typedFromEntries, typedKeys };
250
441
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["missingKeys: Array<keyof T>","result: Partial<T>","result: Partial<T>"],"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/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/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\tthrow new TypeError(`M:${missingKeys.map(String).join()}`);\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","/**\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 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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"}
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-keys.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/invert-object.ts","../src/core/is-empty.ts","../src/core/is-plain-object.ts","../src/core/map-keys.ts","../src/core/map-values.ts","../src/core/omit.ts","../src/core/partition-object.ts","../src/core/pick.ts","../src/core/rename-keys.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 { FilteredKeys, KeyGuard, KeyPredicate } from \"./types\";\n\n/**\n * Filters an object's own enumerable string-keyed properties by key.\n *\n * Supports both boolean predicates and key type guards. The result remains\n * partial because any property may be removed at runtime.\n *\n * @example\n * ```ts\n * const metrics = { total: 5, temp_cache: 2, temp_jobs: 1 } as const;\n *\n * filterKeys(metrics, (key) => key.startsWith(\"temp_\"));\n * // { temp_cache: 2, temp_jobs: 1 }\n * ```\n */\nexport function filterKeys<\n\tT extends object,\n\tS extends Extract<keyof T, string>,\n>(object: T, predicate: KeyGuard<T, S>): FilteredKeys<T, S>;\nexport function filterKeys<T extends object>(\n\tobject: T,\n\tpredicate: KeyPredicate<T>,\n): FilteredKeys<T, Extract<keyof T, string>>;\nexport function filterKeys<T extends object>(\n\tobject: T,\n\tpredicate: KeyPredicate<T>,\n): FilteredKeys<T, Extract<keyof T, string>> {\n\tconst result = {} as FilteredKeys<T, Extract<keyof T, string>>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tif (predicate(key, object[key], object)) {\n\t\t\tresult[key] = object[key];\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","import { typedKeys } from \"./typed-keys\";\nimport type { InvertedObject } from \"./types\";\n\n/**\n * Inverts an object's own enumerable string-keyed properties.\n *\n * Source values must be valid property keys. When multiple source keys share\n * the same value, the later assignment wins.\n *\n * @example\n * ```ts\n * const roles = { admin: \"A\", member: \"M\" } as const;\n *\n * invertObject(roles);\n * // { A: \"admin\", M: \"member\" }\n * ```\n */\nexport function invertObject<T extends Record<string, PropertyKey>>(\n\tobject: T,\n): InvertedObject<T> {\n\tconst result = {} as InvertedObject<T>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst value = object[key] as PropertyKey;\n\n\t\t(result as Record<PropertyKey, string>)[value] = key;\n\t}\n\n\treturn result;\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 { KeyMapper, MappedKeys } from \"./types\";\n\n/**\n * Maps an object's own enumerable string keys to new string keys.\n *\n * When multiple source keys map to the same target key, the later assignment\n * wins.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", active: true } as const;\n *\n * mapKeys(user, (key) => `user_${key}`);\n * // { user_id: \"1\", user_active: true }\n * ```\n */\nexport function mapKeys<T extends object, R extends string>(\n\tobject: T,\n\tmapper: KeyMapper<T, R>,\n): MappedKeys<T, R> {\n\tconst result = {} as MappedKeys<T, R>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst mappedKey = mapper(key, object[key], object);\n\n\t\tresult[mappedKey] = object[key];\n\t}\n\n\treturn result;\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 { typedKeys } from \"./typed-keys\";\nimport type {\n\tPartitionedObject,\n\tPartitionedValues,\n\tValueGuard,\n\tValuePredicate,\n} from \"./types\";\n\n/**\n * Partitions an object's own enumerable string-keyed properties into matching\n * and non-matching objects.\n *\n * Supports both boolean predicates and type-guard predicates.\n *\n * @example\n * ```ts\n * const settings = { retries: 3, label: \"ok\", timeout: null } as const;\n *\n * partitionObject(settings, (value) => value !== null);\n * // [{ retries: 3, label: \"ok\" }, { timeout: null }]\n * ```\n */\nexport function partitionObject<\n\tT extends object,\n\tS extends T[Extract<keyof T, string>],\n>(object: T, predicate: ValueGuard<T, S>): PartitionedValues<T, S>;\nexport function partitionObject<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): PartitionedObject<T>;\nexport function partitionObject<T extends object>(\n\tobject: T,\n\tpredicate: ValuePredicate<T>,\n): PartitionedObject<T> {\n\tconst matching = {} as PartitionedObject<T>[0];\n\tconst rest = {} as PartitionedObject<T>[1];\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\t(matching as Record<string, T[Extract<keyof T, string>]>)[key] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\t(rest as Record<string, T[Extract<keyof T, string>]>)[key] = value;\n\t}\n\n\treturn [matching, rest];\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 { hasOwn } from \"./has-own\";\nimport { typedKeys } from \"./typed-keys\";\nimport type { RenamedKeys } from \"./types\";\n\n/**\n * Renames selected own enumerable string-keyed properties using a key map.\n *\n * Unmapped keys are copied through unchanged. When multiple source keys resolve\n * to the same target key, the later assignment wins.\n *\n * @example\n * ```ts\n * const user = { id: \"1\", givenName: \"Umsizi\" } as const;\n *\n * renameKeys(user, { givenName: \"name\" });\n * // { id: \"1\", name: \"Umsizi\" }\n * ```\n */\nexport function renameKeys<\n\tT extends object,\n\tconst M extends Partial<Record<Extract<keyof T, string>, string>>,\n>(object: T, names: M): RenamedKeys<T, M> {\n\tconst result = {} as RenamedKeys<T, M>;\n\n\tfor (const key of typedKeys(object)) {\n\t\tconst renamedKey = (hasOwn(names, key) ? names[key] : key) as string;\n\n\t\t(result as Record<string, T[Extract<keyof T, string>]>)[renamedKey] =\n\t\t\tobject[key];\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
- * Query strings and fragments are treated as opaque path characters and are
11
- * not parsed or stripped pass only the pathname segment of a URL.
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
- * Query strings and fragments are treated as opaque path characters and are
11
- * not parsed or stripped pass only the pathname segment of a URL.
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
- if (pathname === "") return "/";
22
- const normalized = pathname.replace(/\/{2,}/g, "/").replace(/\/$/, "");
23
- if (normalized === "") return "/";
24
- return normalized.startsWith("/") ? normalized : `/${normalized}`;
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 * Query strings and fragments are treated as opaque path characters and are\n * not parsed or stripped pass only the pathname segment of a URL.\n *\n * @example\n * ```ts\n * normalizePathname(\"dashboard\"); // \"/dashboard\"\n * normalizePathname(\"//dashboard///settings/\"); // \"/dashboard/settings\"\n * normalizePathname(\"\"); // \"/\"\n * ```\n */\nexport function normalizePathname(pathname: string): string {\n\tif (pathname === \"\") {\n\t\treturn \"/\";\n\t}\n\n\tconst normalized = pathname.replace(/\\/{2,}/g, \"/\").replace(/\\/$/, \"\");\n\n\tif (normalized === \"\") {\n\t\treturn \"/\";\n\t}\n\n\treturn normalized.startsWith(\"/\") ? normalized : `/${normalized}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,SAAgB,kBAAkB,UAA0B;AAC3D,KAAI,aAAa,GAChB,QAAO;CAGR,MAAM,aAAa,SAAS,QAAQ,WAAW,IAAI,CAAC,QAAQ,OAAO,GAAG;AAEtE,KAAI,eAAe,GAClB,QAAO;AAGR,QAAO,WAAW,WAAW,IAAI,GAAG,aAAa,IAAI"}
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.5.0",
3
+ "version": "0.7.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": "512 B"
75
+ "limit": "1 KB"
76
76
  },
77
77
  {
78
78
  "name": "umsizi/react",