@valkyriestudios/utils 12.40.0 → 12.41.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
@@ -12,6 +12,11 @@ Zero-dependency collection of single-function utilities for common tasks
12
12
  ## Installation
13
13
  `npm install @valkyriestudios/utils`
14
14
 
15
+ ## 🧊 TriFrost is powered by utils
16
+ Many of the utilities in this package are optimized and tested as foundational building blocks of [TriFrost](https://www.trifrost.dev) — a high-performance, type-safe framework for building fullstack TypeScript applications.
17
+
18
+ If you're looking to go beyond utilities and build fully modular backends with deep type integration, check out TriFrost.
19
+
15
20
  ## Available Functions
16
21
  ### array/is(val:unknown)
17
22
  Check if a variable is of type Array
@@ -1498,7 +1503,7 @@ pick({a: 1, b: 2, c: 3}, ['a','b']); // {a: 1, b: 2}
1498
1503
  ### object/omit(obj:Object={}, keys:Array[string]=[])
1499
1504
  Returns an object with the keys provided in the keys array stripped from the provided object.
1500
1505
  ```typescript
1501
- import { omit } from "@valkyriestudios/utils/object"; /* Or @valkyriestudios/utils/object/omit; */
1506
+ import { omit } from "@valkyriestudios/utils/object";
1502
1507
  const redacted = omit({
1503
1508
  firstName: "Peter",
1504
1509
  lastName: "Vermeulen",
@@ -1519,6 +1524,89 @@ Its type will be
1519
1524
  */
1520
1525
  ```
1521
1526
 
1527
+ Also works with wildcards (take note, only as **prefix**):
1528
+ ```typescript
1529
+ import { omit } from "@valkyriestudios/utils/object";
1530
+ const redacted = omit({
1531
+ firstName: "Peter",
1532
+ lastName: "Vermeulen",
1533
+ age: 34,
1534
+ details: {
1535
+ phone: "...",
1536
+ email: "...",
1537
+ isActive: true,
1538
+ password: "...",
1539
+ },
1540
+ meta: {
1541
+ phone: "...",
1542
+ },
1543
+ }, ["age", "*.phone", "*.email", "*.password"]);
1544
+ /**
1545
+ Redacted here will be:
1546
+ {
1547
+ firstName: "Peter",
1548
+ lastName: "Vermeulen",
1549
+ details: {isActive: true},
1550
+ meta: {}
1551
+ }
1552
+ */
1553
+ ```
1554
+
1555
+ ### object/scramble(obj:Object={}, keys:Array[string]=[], options?:{replacement?:string})
1556
+ Returns an object with the keys provided in the keys array scrambled.
1557
+ ```typescript
1558
+ import { scramble } from "@valkyriestudios/utils/object";
1559
+ const redacted = scramble({
1560
+ firstName: "Peter",
1561
+ lastName: "Vermeulen",
1562
+ age: 34,
1563
+ details: {
1564
+ phone: "...",
1565
+ email: "...",
1566
+ isActive: true,
1567
+ password: "...",
1568
+ },
1569
+ }, ["age", "details.phone", "details.email", "details.password"]);
1570
+ /**
1571
+ Redacted here will be:
1572
+ {
1573
+ firstName: "Peter",
1574
+ lastName: "Vermeulen",
1575
+ age: "***",
1576
+ details: {phone: "***", email: "***", isActive: true, password: "***"}
1577
+ }
1578
+ */
1579
+ ```
1580
+
1581
+ Also works with wildcards (take note, only as **prefix**):
1582
+ ```typescript
1583
+ import { scramble } from "@valkyriestudios/utils/object";
1584
+ const redacted = scramble({
1585
+ firstName: "Peter",
1586
+ lastName: "Vermeulen",
1587
+ age: 34,
1588
+ details: {
1589
+ phone: "...",
1590
+ email: "...",
1591
+ isActive: true,
1592
+ password: "...",
1593
+ },
1594
+ meta: {
1595
+ phone: "...",
1596
+ },
1597
+ }, ["age", "*.phone", "*.email", "*.password"]);
1598
+ /**
1599
+ Redacted here will be:
1600
+ {
1601
+ firstName: "Peter",
1602
+ lastName: "Vermeulen",
1603
+ age: "***",
1604
+ details: {phone: "***", email: "***", isActive: true, password: "***"},
1605
+ meta: {phone: "***"}
1606
+ }
1607
+ */
1608
+ ```
1609
+
1522
1610
  ### object/merge(target:Object={},obj:Object|Object[]={}, opts?:{union?:boolean})
1523
1611
  Merges two objects together, with the preference over the second object.
1524
1612
  ```typescript
@@ -6,7 +6,7 @@ const isFormat_1 = require("../date/isFormat");
6
6
  const RGX_TOKENS = /[^.[\]]+/g;
7
7
  function assign(acc, rawkey, value, single) {
8
8
  let cursor = acc;
9
- const keys = rawkey.match(RGX_TOKENS) || [];
9
+ const keys = rawkey.match(RGX_TOKENS);
10
10
  const keys_len = keys.length;
11
11
  for (let i = 0; i < keys_len; i++) {
12
12
  const key = keys[i];
@@ -2,32 +2,84 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.omit = omit;
4
4
  exports.default = omit;
5
- function innerOmit(obj, keys) {
6
- const result = { ...obj };
7
- for (let i = 0; i < keys.length; i++) {
8
- const key = keys[i];
9
- if (typeof key !== 'string')
10
- continue;
11
- let target = result;
12
- const parts = key.split('.');
13
- const last = parts.length - 1;
14
- for (let j = 0; j < last; j++) {
15
- const part = parts[j];
16
- const val = target[part];
17
- if (Object.prototype.toString.call(val) === '[object Object]') {
18
- if (target[part] === obj[part]) {
19
- target[part] = { ...val };
5
+ function wildcardProp(target, source, prop) {
6
+ if (Array.isArray(target)) {
7
+ for (let i = 0; i < target.length; i++) {
8
+ const t = target[i];
9
+ const s = source[i];
10
+ if (typeof t === 'object' && t !== null && typeof s === 'object' && s !== null) {
11
+ if (t === s)
12
+ target[i] = { ...t };
13
+ wildcardProp(target[i], s, prop);
14
+ }
15
+ }
16
+ }
17
+ else if (Object.prototype.toString.call(target) === '[object Object]') {
18
+ for (const key in target) {
19
+ if (key === prop && key in source) {
20
+ delete target[key];
21
+ }
22
+ else {
23
+ const val = target[key];
24
+ const s_val = source?.[key];
25
+ if (typeof val === 'object' && typeof s_val === 'object' && val !== null && s_val !== null) {
26
+ if (val === s_val) {
27
+ target[key] = Array.isArray(val) ? [...val] : { ...val };
28
+ }
29
+ wildcardProp(target[key], s_val, prop);
20
30
  }
21
- target = target[part];
22
31
  }
23
32
  }
24
- delete target[parts[last]];
25
33
  }
26
- return result;
34
+ }
35
+ function standardProp(target, source, path) {
36
+ const last = path.length - 1;
37
+ for (let i = 0; i < last; i++) {
38
+ const key = path[i];
39
+ const val = target[key];
40
+ const src_val = source?.[key];
41
+ if (Array.isArray(val)) {
42
+ target[key] = val.map((item, idx) => {
43
+ const src_item = src_val[idx];
44
+ if (Object.prototype.toString.call(item) === '[object Object]') {
45
+ const clone = { ...item };
46
+ standardProp(clone, src_item, path.slice(i + 1));
47
+ return clone;
48
+ }
49
+ return item;
50
+ });
51
+ return;
52
+ }
53
+ if (Object.prototype.toString.call(val) === '[object Object]') {
54
+ if (val === src_val) {
55
+ target[key] = { ...val };
56
+ }
57
+ target = target[key];
58
+ source = src_val;
59
+ }
60
+ else {
61
+ return;
62
+ }
63
+ }
64
+ if (target && typeof target === 'object' && path[last] in source) {
65
+ delete target[path[last]];
66
+ }
27
67
  }
28
68
  function omit(obj, keys) {
29
69
  if (Object.prototype.toString.call(obj) !== '[object Object]' ||
30
70
  !Array.isArray(keys))
31
71
  throw new TypeError('Please pass an object to omit from and a keys array');
32
- return innerOmit(obj, keys);
72
+ const result = { ...obj };
73
+ for (let i = 0; i < keys.length; i++) {
74
+ const key = keys[i];
75
+ if (typeof key === 'string') {
76
+ if (key.length > 2 && key[0] === '*' && key[1] === '.') {
77
+ wildcardProp(result, obj, key.slice(2));
78
+ }
79
+ else {
80
+ standardProp(result, obj, key.split('.'));
81
+ }
82
+ }
83
+ }
84
+ return result;
33
85
  }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function wildcardProp(target, source, prop, repl) {
4
+ if (Array.isArray(target)) {
5
+ for (let i = 0; i < target.length; i++) {
6
+ const t = target[i];
7
+ const s = source[i];
8
+ if (typeof t === 'object' && t !== null && typeof s === 'object' && s !== null) {
9
+ if (t === s)
10
+ target[i] = { ...t };
11
+ wildcardProp(target[i], s, prop, repl);
12
+ }
13
+ }
14
+ }
15
+ else if (Object.prototype.toString.call(target) === '[object Object]') {
16
+ for (const key in target) {
17
+ if (key === prop && key in source) {
18
+ target[key] = repl;
19
+ }
20
+ else {
21
+ const val = target[key];
22
+ const s_val = source?.[key];
23
+ if (typeof val === 'object' && typeof s_val === 'object' && val !== null && s_val !== null) {
24
+ if (val === s_val) {
25
+ target[key] = Array.isArray(val) ? [...val] : { ...val };
26
+ }
27
+ wildcardProp(target[key], s_val, prop, repl);
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ function standardProp(target, source, path, repl) {
34
+ const last = path.length - 1;
35
+ for (let i = 0; i < last; i++) {
36
+ const key = path[i];
37
+ const val = target[key];
38
+ const src_val = source?.[key];
39
+ if (Array.isArray(val)) {
40
+ target[key] = val.map((item, idx) => {
41
+ const src_item = src_val[idx];
42
+ if (Object.prototype.toString.call(item) === '[object Object]') {
43
+ const clone = { ...item };
44
+ standardProp(clone, src_item, path.slice(i + 1), repl);
45
+ return clone;
46
+ }
47
+ return item;
48
+ });
49
+ return;
50
+ }
51
+ else if (Object.prototype.toString.call(val) === '[object Object]') {
52
+ if (val === src_val) {
53
+ target[key] = { ...val };
54
+ }
55
+ target = target[key];
56
+ source = src_val;
57
+ }
58
+ else {
59
+ return;
60
+ }
61
+ }
62
+ if (target && typeof target === 'object' && path[last] in source) {
63
+ target[path[last]] = repl;
64
+ }
65
+ }
66
+ function scramble(obj, keys, options) {
67
+ if (Object.prototype.toString.call(obj) !== '[object Object]' ||
68
+ !Array.isArray(keys))
69
+ throw new TypeError('Please pass an object to scramble and a keys array');
70
+ const repl = typeof options?.replacement === 'string' ? options.replacement : '***';
71
+ const result = { ...obj };
72
+ for (let i = 0; i < keys.length; i++) {
73
+ const key = keys[i];
74
+ if (typeof key === 'string') {
75
+ if (key.length > 2 && key[0] === '*' && key[1] === '.') {
76
+ wildcardProp(result, obj, key.slice(2), repl);
77
+ }
78
+ else {
79
+ standardProp(result, obj, key.split('.'), repl);
80
+ }
81
+ }
82
+ }
83
+ return result;
84
+ }
85
+ exports.default = scramble;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -2,7 +2,7 @@ import { isDateFormat } from '../date/isFormat';
2
2
  const RGX_TOKENS = /[^.[\]]+/g;
3
3
  function assign(acc, rawkey, value, single) {
4
4
  let cursor = acc;
5
- const keys = rawkey.match(RGX_TOKENS) || [];
5
+ const keys = rawkey.match(RGX_TOKENS);
6
6
  const keys_len = keys.length;
7
7
  for (let i = 0; i < keys_len; i++) {
8
8
  const key = keys[i];
@@ -1,30 +1,82 @@
1
- function innerOmit(obj, keys) {
2
- const result = { ...obj };
3
- for (let i = 0; i < keys.length; i++) {
4
- const key = keys[i];
5
- if (typeof key !== 'string')
6
- continue;
7
- let target = result;
8
- const parts = key.split('.');
9
- const last = parts.length - 1;
10
- for (let j = 0; j < last; j++) {
11
- const part = parts[j];
12
- const val = target[part];
13
- if (Object.prototype.toString.call(val) === '[object Object]') {
14
- if (target[part] === obj[part]) {
15
- target[part] = { ...val };
1
+ function wildcardProp(target, source, prop) {
2
+ if (Array.isArray(target)) {
3
+ for (let i = 0; i < target.length; i++) {
4
+ const t = target[i];
5
+ const s = source[i];
6
+ if (typeof t === 'object' && t !== null && typeof s === 'object' && s !== null) {
7
+ if (t === s)
8
+ target[i] = { ...t };
9
+ wildcardProp(target[i], s, prop);
10
+ }
11
+ }
12
+ }
13
+ else if (Object.prototype.toString.call(target) === '[object Object]') {
14
+ for (const key in target) {
15
+ if (key === prop && key in source) {
16
+ delete target[key];
17
+ }
18
+ else {
19
+ const val = target[key];
20
+ const s_val = source?.[key];
21
+ if (typeof val === 'object' && typeof s_val === 'object' && val !== null && s_val !== null) {
22
+ if (val === s_val) {
23
+ target[key] = Array.isArray(val) ? [...val] : { ...val };
24
+ }
25
+ wildcardProp(target[key], s_val, prop);
16
26
  }
17
- target = target[part];
18
27
  }
19
28
  }
20
- delete target[parts[last]];
21
29
  }
22
- return result;
30
+ }
31
+ function standardProp(target, source, path) {
32
+ const last = path.length - 1;
33
+ for (let i = 0; i < last; i++) {
34
+ const key = path[i];
35
+ const val = target[key];
36
+ const src_val = source?.[key];
37
+ if (Array.isArray(val)) {
38
+ target[key] = val.map((item, idx) => {
39
+ const src_item = src_val[idx];
40
+ if (Object.prototype.toString.call(item) === '[object Object]') {
41
+ const clone = { ...item };
42
+ standardProp(clone, src_item, path.slice(i + 1));
43
+ return clone;
44
+ }
45
+ return item;
46
+ });
47
+ return;
48
+ }
49
+ if (Object.prototype.toString.call(val) === '[object Object]') {
50
+ if (val === src_val) {
51
+ target[key] = { ...val };
52
+ }
53
+ target = target[key];
54
+ source = src_val;
55
+ }
56
+ else {
57
+ return;
58
+ }
59
+ }
60
+ if (target && typeof target === 'object' && path[last] in source) {
61
+ delete target[path[last]];
62
+ }
23
63
  }
24
64
  function omit(obj, keys) {
25
65
  if (Object.prototype.toString.call(obj) !== '[object Object]' ||
26
66
  !Array.isArray(keys))
27
67
  throw new TypeError('Please pass an object to omit from and a keys array');
28
- return innerOmit(obj, keys);
68
+ const result = { ...obj };
69
+ for (let i = 0; i < keys.length; i++) {
70
+ const key = keys[i];
71
+ if (typeof key === 'string') {
72
+ if (key.length > 2 && key[0] === '*' && key[1] === '.') {
73
+ wildcardProp(result, obj, key.slice(2));
74
+ }
75
+ else {
76
+ standardProp(result, obj, key.split('.'));
77
+ }
78
+ }
79
+ }
80
+ return result;
29
81
  }
30
82
  export { omit, omit as default };
@@ -0,0 +1,83 @@
1
+ function wildcardProp(target, source, prop, repl) {
2
+ if (Array.isArray(target)) {
3
+ for (let i = 0; i < target.length; i++) {
4
+ const t = target[i];
5
+ const s = source[i];
6
+ if (typeof t === 'object' && t !== null && typeof s === 'object' && s !== null) {
7
+ if (t === s)
8
+ target[i] = { ...t };
9
+ wildcardProp(target[i], s, prop, repl);
10
+ }
11
+ }
12
+ }
13
+ else if (Object.prototype.toString.call(target) === '[object Object]') {
14
+ for (const key in target) {
15
+ if (key === prop && key in source) {
16
+ target[key] = repl;
17
+ }
18
+ else {
19
+ const val = target[key];
20
+ const s_val = source?.[key];
21
+ if (typeof val === 'object' && typeof s_val === 'object' && val !== null && s_val !== null) {
22
+ if (val === s_val) {
23
+ target[key] = Array.isArray(val) ? [...val] : { ...val };
24
+ }
25
+ wildcardProp(target[key], s_val, prop, repl);
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
31
+ function standardProp(target, source, path, repl) {
32
+ const last = path.length - 1;
33
+ for (let i = 0; i < last; i++) {
34
+ const key = path[i];
35
+ const val = target[key];
36
+ const src_val = source?.[key];
37
+ if (Array.isArray(val)) {
38
+ target[key] = val.map((item, idx) => {
39
+ const src_item = src_val[idx];
40
+ if (Object.prototype.toString.call(item) === '[object Object]') {
41
+ const clone = { ...item };
42
+ standardProp(clone, src_item, path.slice(i + 1), repl);
43
+ return clone;
44
+ }
45
+ return item;
46
+ });
47
+ return;
48
+ }
49
+ else if (Object.prototype.toString.call(val) === '[object Object]') {
50
+ if (val === src_val) {
51
+ target[key] = { ...val };
52
+ }
53
+ target = target[key];
54
+ source = src_val;
55
+ }
56
+ else {
57
+ return;
58
+ }
59
+ }
60
+ if (target && typeof target === 'object' && path[last] in source) {
61
+ target[path[last]] = repl;
62
+ }
63
+ }
64
+ function scramble(obj, keys, options) {
65
+ if (Object.prototype.toString.call(obj) !== '[object Object]' ||
66
+ !Array.isArray(keys))
67
+ throw new TypeError('Please pass an object to scramble and a keys array');
68
+ const repl = typeof options?.replacement === 'string' ? options.replacement : '***';
69
+ const result = { ...obj };
70
+ for (let i = 0; i < keys.length; i++) {
71
+ const key = keys[i];
72
+ if (typeof key === 'string') {
73
+ if (key.length > 2 && key[0] === '*' && key[1] === '.') {
74
+ wildcardProp(result, obj, key.slice(2), repl);
75
+ }
76
+ else {
77
+ standardProp(result, obj, key.split('.'), repl);
78
+ }
79
+ }
80
+ }
81
+ return result;
82
+ }
83
+ export default scramble;
@@ -0,0 +1 @@
1
+ export {};
package/index.d.ts CHANGED
@@ -379,13 +379,25 @@ declare module "deep/get" {
379
379
  function deepGet<T extends ObjectType | ArrayType, P extends string>(obj: T, path: P, get_parent?: boolean): DeepGetResult<T, P> | undefined;
380
380
  export { deepGet, deepGet as default };
381
381
  }
382
+ declare module "object/types" {
383
+ export type DottedKeys<T> = (T extends Record<string, any> ? {
384
+ [K in keyof T & string]: T[K] extends Record<string, any> ? K | `${K}.${DottedKeys<T[K]>}` : K;
385
+ }[keyof T & string] : string) & string;
386
+ export type DottedKeysWithArray<T> = (T extends Record<string, any> ? {
387
+ [K in keyof T & string]: T[K] extends (infer U)[] ? U extends Record<string, any> ? K | `${K}.${DottedKeysWithArray<U>}` : K : T[K] extends Record<string, any> ? K | `${K}.${DottedKeysWithArray<T[K]>}` : K;
388
+ }[keyof T & string] : string) & string;
389
+ export type ExpandWildcard<T, P extends string> = P extends `*.${infer Key}` ? {
390
+ [K in keyof T]: T[K] extends Record<string, any> ? `${K & string}.${Key}` : never;
391
+ }[keyof T] : P;
392
+ export type ExpandWildcardWithArray<T, P extends string> = P extends `*.${infer Key}` ? {
393
+ [K in keyof T]: T[K] extends (infer U)[] ? U extends Record<string, any> ? `${K & string}.${Key}` : never : T[K] extends Record<string, any> ? `${K & string}.${Key}` : never;
394
+ }[keyof T] : P;
395
+ }
382
396
  declare module "object/pick" {
397
+ import { type DottedKeys } from "object/types";
383
398
  type ObjectType = {
384
399
  [key: string]: any;
385
400
  };
386
- type DottedKeys<T> = (T extends ObjectType ? {
387
- [K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
388
- }[keyof T & string] : string) & string;
389
401
  type PickFromObject<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType ? {
390
402
  [P in Key]: PickFromObject<T[Key], Rest>;
391
403
  } : object : object : K extends keyof T ? {
@@ -396,16 +408,11 @@ declare module "object/pick" {
396
408
  export { pick, pick as default };
397
409
  }
398
410
  declare module "object/omit" {
399
- type ObjectType = {
400
- [key: string]: any;
401
- };
402
- type DottedKeys<T> = (T extends ObjectType ? {
403
- [K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
404
- }[keyof T & string] : string) & string;
405
- type OmitFromObject<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType ? {
411
+ import { type DottedKeysWithArray, type ExpandWildcardWithArray } from "object/types";
412
+ type OmitFromObject<T, K extends string> = T extends (infer U)[] ? OmitFromObject<U, K>[] : T extends Record<string, any> ? K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends Record<string, any> | any[] ? {
406
413
  [P in keyof T]: P extends Key ? OmitFromObject<T[Key], Rest> : T[P];
407
- } : T : T : Omit<T, K>;
408
- function omit<T extends Record<string, any>, K extends readonly DottedKeys<T>[]>(obj: T, keys: K): OmitFromObject<T, K[number]>;
414
+ } : T : T : Omit<T, K> : T;
415
+ function omit<T extends Record<string, any>, K extends readonly (DottedKeysWithArray<T> | `*.${string}`)[]>(obj: T, keys: K): OmitFromObject<T, ExpandWildcardWithArray<T, K[number]>>;
409
416
  export { omit, omit as default };
410
417
  }
411
418
  declare module "object/index" {
@@ -777,3 +784,10 @@ declare module "modules/index" {
777
784
  export { PubSub } from "modules/PubSub";
778
785
  export { Scheduler } from "modules/Scheduler";
779
786
  }
787
+ declare module "object/scramble" {
788
+ import { type DottedKeysWithArray } from "object/types";
789
+ function scramble<T extends Record<string, any>, K extends readonly (DottedKeysWithArray<T> | `*.${string}`)[]>(obj: T, keys: K, options?: {
790
+ replacement?: string;
791
+ }): T;
792
+ export default scramble;
793
+ }
package/object/omit.d.ts CHANGED
@@ -1,17 +1,16 @@
1
- type ObjectType = {
2
- [key: string]: any;
3
- };
4
- type DottedKeys<T> = (T extends ObjectType ? {
5
- [K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
6
- }[keyof T & string] : string) & string;
7
- type OmitFromObject<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType ? {
1
+ import { type DottedKeysWithArray, type ExpandWildcardWithArray } from './types';
2
+ type OmitFromObject<T, K extends string> = T extends (infer U)[] ? OmitFromObject<U, K>[] : T extends Record<string, any> ? K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends Record<string, any> | any[] ? {
8
3
  [P in keyof T]: P extends Key ? OmitFromObject<T[Key], Rest> : T[P];
9
- } : T : T : Omit<T, K>;
4
+ } : T : T : Omit<T, K> : T;
10
5
  /**
11
- * Returns a new object with the keys omitted from the passed object, handling nested keys recursively
6
+ * Returns a new object with the provided keys omitted
7
+ * Supports:
8
+ * - omitting keys in nested arrays
9
+ * - omitting wildcard patterns: '*.password'
10
+ * - omitting standard keys
12
11
  *
13
12
  * @param {Record<string, any>} obj - Object to omit from
14
13
  * @param {string[]} keys - Array of keys to omit from object
15
14
  */
16
- declare function omit<T extends Record<string, any>, K extends readonly DottedKeys<T>[]>(obj: T, keys: K): OmitFromObject<T, K[number]>;
15
+ declare function omit<T extends Record<string, any>, K extends readonly (DottedKeysWithArray<T> | `*.${string}`)[]>(obj: T, keys: K): OmitFromObject<T, ExpandWildcardWithArray<T, K[number]>>;
17
16
  export { omit, omit as default };
package/object/pick.d.ts CHANGED
@@ -1,9 +1,7 @@
1
+ import { type DottedKeys } from './types';
1
2
  type ObjectType = {
2
3
  [key: string]: any;
3
4
  };
4
- type DottedKeys<T> = (T extends ObjectType ? {
5
- [K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
6
- }[keyof T & string] : string) & string;
7
5
  type PickFromObject<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType ? {
8
6
  [P in Key]: PickFromObject<T[Key], Rest>;
9
7
  } : object : object : K extends keyof T ? {
@@ -0,0 +1,15 @@
1
+ import { type DottedKeysWithArray } from './types';
2
+ /**
3
+ * Returns a new object with the provided keys obfuscated
4
+ * Supports:
5
+ * - scrambling keys in nested arrays
6
+ * - scrambling wildcard patterns: '*.password'
7
+ * - scrambling standard keys
8
+ *
9
+ * @param {Record<string, any>} obj - Object to omit from
10
+ * @param {string[]} keys - Array of keys to omit from object
11
+ */
12
+ declare function scramble<T extends Record<string, any>, K extends readonly (DottedKeysWithArray<T> | `*.${string}`)[]>(obj: T, keys: K, options?: {
13
+ replacement?: string;
14
+ }): T;
15
+ export default scramble;
@@ -0,0 +1,12 @@
1
+ export type DottedKeys<T> = (T extends Record<string, any> ? {
2
+ [K in keyof T & string]: T[K] extends Record<string, any> ? K | `${K}.${DottedKeys<T[K]>}` : K;
3
+ }[keyof T & string] : string) & string;
4
+ export type DottedKeysWithArray<T> = (T extends Record<string, any> ? {
5
+ [K in keyof T & string]: T[K] extends (infer U)[] ? U extends Record<string, any> ? K | `${K}.${DottedKeysWithArray<U>}` : K : T[K] extends Record<string, any> ? K | `${K}.${DottedKeysWithArray<T[K]>}` : K;
6
+ }[keyof T & string] : string) & string;
7
+ export type ExpandWildcard<T, P extends string> = P extends `*.${infer Key}` ? {
8
+ [K in keyof T]: T[K] extends Record<string, any> ? `${K & string}.${Key}` : never;
9
+ }[keyof T] : P;
10
+ export type ExpandWildcardWithArray<T, P extends string> = P extends `*.${infer Key}` ? {
11
+ [K in keyof T]: T[K] extends (infer U)[] ? U extends Record<string, any> ? `${K & string}.${Key}` : never : T[K] extends Record<string, any> ? `${K & string}.${Key}` : never;
12
+ }[keyof T] : P;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valkyriestudios/utils",
3
- "version": "12.40.0",
3
+ "version": "12.41.0",
4
4
  "description": "A collection of single-function utilities for common tasks",
5
5
  "author": {
6
6
  "name": "Peter Vermeulen",
@@ -457,6 +457,11 @@
457
457
  "import": "./esm/object/pick.js",
458
458
  "require": "./cjs/object/pick.js"
459
459
  },
460
+ "./object/scramble": {
461
+ "types": "./object/scramble.d.ts",
462
+ "import": "./esm/object/scramble.js",
463
+ "require": "./cjs/object/scramble.js"
464
+ },
460
465
  "./regexp": {
461
466
  "types": "./regexp/index.d.ts",
462
467
  "import": "./esm/regexp/index.js",
@@ -509,12 +514,12 @@
509
514
  }
510
515
  },
511
516
  "devDependencies": {
512
- "@types/node": "^22.15.29",
513
- "@vitest/coverage-v8": "^3.2.1",
517
+ "@types/node": "^22.15.30",
518
+ "@vitest/coverage-v8": "^3.2.2",
514
519
  "esbuild-register": "^3.6.0",
515
520
  "eslint": "^9.28.0",
516
521
  "typescript": "^5.8.3",
517
522
  "typescript-eslint": "^8.33.1",
518
- "vitest": "^3.2.1"
523
+ "vitest": "^3.2.2"
519
524
  }
520
525
  }