@valkyriestudios/utils 12.25.1 → 12.27.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
@@ -493,8 +493,8 @@ Format a date according to a spec/locale and zone
493
493
  | `W` | Week Number as pure digit | 1 2 .. 52 53 |
494
494
  | `DD` | Day of month as 2 char | 01 02 .. 30 31 |
495
495
  | `D` | Day of month as 1 char | 1 2 .. 30 31 |
496
- | `dddd` | Day of week as 3 char | Sun Mon ... Fri Sat |
497
- | `ddd` | Day of week in full | Sunday Monday ... Saturday |
496
+ | `dddd` | Day of week in full | Sunday Monday ... Saturday |
497
+ | `ddd` | Day of week as 3 char | Sun Mon ... Fri Sat |
498
498
  | `HH` | Hours as 2-char | 00 01 .. 22 23 |
499
499
  | `H` | Hours as pure digit | 0 1 .. 22 23 |
500
500
  | `hh` | Hours in 12 hour time as 2 char | 01 02 ... 11 12 |
@@ -1150,13 +1150,37 @@ isNotEmptyObject('Hi'); // FALSE
1150
1150
  ```
1151
1151
 
1152
1152
  ### object/pick(obj:Object={}, keys:Array[string]=[])
1153
- Copies the keys passed in the 'keys' array from the passed object to a new object and returns that object.**
1153
+ Copies the keys passed in the 'keys' array from the passed object to a new object and returns that object.
1154
1154
  <small>If a key wasn't found it will be set as undefined</small>
1155
1155
  ```typescript
1156
1156
  import pick from '@valkyriestudios/utils/object/pick';
1157
1157
  pick({a: 1, b: 2, c: 3}, ['a','b']); // {a: 1, b: 2}
1158
1158
  ```
1159
1159
 
1160
+ ### object/omit(obj:Object={}, keys:Array[string]=[])
1161
+ Returns an object with the keys provided in the keys array stripped from the provided object.
1162
+ ```typescript
1163
+ import { omit } from "@valkyriestudios/utils/object"; /* Or @valkyriestudios/utils/object/omit; */
1164
+ const redacted = omit({
1165
+ firstName: "Peter",
1166
+ lastName: "Vermeulen",
1167
+ age: 34,
1168
+ details: {
1169
+ phone: "...",
1170
+ email: "...",
1171
+ isActive: true,
1172
+ password: "...",
1173
+ },
1174
+ }, ["age", "details.phone", "details.email", "details.password"]);
1175
+ /**
1176
+ Redacted here will be:
1177
+ {firstName: "Peter", lastName: "Vermeulen", "details": {"isActive": true}}
1178
+
1179
+ Its type will be
1180
+ {firstName: string; lastName: string; details: {isActive: boolean}}
1181
+ */
1182
+ ```
1183
+
1160
1184
  ### object/merge(target:Object={},obj:Object|Object[]={}, opts?:{union?:boolean})
1161
1185
  Merges two objects together, with the preference over the second object.
1162
1186
  ```typescript
@@ -4,45 +4,45 @@ exports.toObject = toObject;
4
4
  exports.default = toObject;
5
5
  const isFormat_1 = require("../date/isFormat");
6
6
  const RGX_CLOSE = /\]/g;
7
+ const RGX_DIGIT = /^\d+$/;
7
8
  function assignValue(acc, rawkey, value, single) {
8
9
  let cursor = acc;
9
10
  const keys = rawkey.replace(RGX_CLOSE, '').split(/\[|\./);
10
11
  const keys_len = keys.length;
11
12
  for (let i = 0; i < keys_len; i++) {
12
13
  const key = keys[i];
13
- if (i === keys_len - 1) {
14
+ if (i < (keys_len - 1)) {
15
+ const n_key = Array.isArray(cursor) ? Number(key) : key;
16
+ if (!cursor[n_key]) {
17
+ cursor[n_key] = RGX_DIGIT.test(keys[i + 1]) ? [] : {};
18
+ }
19
+ cursor = cursor[n_key];
20
+ }
21
+ else if (!(key in cursor) || single.has(key)) {
22
+ cursor[key] = value;
23
+ }
24
+ else {
14
25
  const cursor_val = cursor[key];
15
- if (cursor_val !== undefined && (!single || !single.has(key))) {
16
- if (Array.isArray(cursor_val)) {
17
- cursor[key].push(value);
18
- }
19
- else {
20
- cursor[key] = [cursor_val, value];
21
- }
26
+ if (Array.isArray(cursor_val)) {
27
+ cursor_val.push(value);
22
28
  }
23
29
  else {
24
- cursor[key] = value;
30
+ cursor[key] = [cursor_val, value];
25
31
  }
26
32
  }
27
- else {
28
- const n_key = Array.isArray(cursor) ? Number(key) : key;
29
- if (!cursor[n_key])
30
- cursor[n_key] = isNaN(Number(keys[i + 1])) ? {} : [];
31
- cursor = cursor[n_key];
32
- }
33
33
  }
34
34
  }
35
35
  function toObject(form, config) {
36
36
  if (!(form instanceof FormData))
37
37
  throw new Error('formdata/toObject: Value is not an instance of FormData');
38
38
  const set = config?.raw === true ? true : new Set(Array.isArray(config?.raw) ? config?.raw : []);
39
- const single = Array.isArray(config?.single) && config?.single.length ? new Set(config.single) : null;
39
+ const single = new Set(Array.isArray(config?.single) ? config.single : []);
40
40
  const nBool = config?.normalize_bool !== false;
41
41
  const nDate = config?.normalize_date !== false;
42
42
  const nNumber = config?.normalize_number !== false;
43
43
  const acc = {};
44
44
  form.forEach((value, key) => {
45
- if (set !== true && typeof value === 'string' && !set.has(key)) {
45
+ if (set !== true && typeof value === 'string' && value !== '' && !set.has(key)) {
46
46
  if (nBool) {
47
47
  const lower = value.toLowerCase();
48
48
  if (lower === 'true') {
@@ -54,17 +54,17 @@ function toObject(form, config) {
54
54
  return;
55
55
  }
56
56
  }
57
- const trimmed = value.trim();
58
- if (trimmed.length) {
59
- if (nNumber && !isNaN(Number(value))) {
60
- assignValue(acc, key, Number(value), single);
61
- return;
62
- }
63
- if (nDate && (0, isFormat_1.isDateFormat)(value, 'ISO')) {
64
- assignValue(acc, key, new Date(value), single);
57
+ if (nNumber) {
58
+ const nVal = Number(value);
59
+ if (!isNaN(nVal)) {
60
+ assignValue(acc, key, nVal, single);
65
61
  return;
66
62
  }
67
63
  }
64
+ if (nDate && (0, isFormat_1.isDateFormat)(value, 'ISO')) {
65
+ assignValue(acc, key, new Date(value), single);
66
+ return;
67
+ }
68
68
  }
69
69
  assignValue(acc, key, value, single);
70
70
  });
package/index.d.ts CHANGED
@@ -342,13 +342,27 @@ declare module "object/pick" {
342
342
  function pick<T extends Record<string, any>, K extends readonly DottedKeys<T>[]>(obj: T, keys: K): UnionToIntersection<PickFromObject<T, K[number]>>;
343
343
  export { pick, pick as default };
344
344
  }
345
+ declare module "object/omit" {
346
+ type ObjectType = {
347
+ [key: string]: any;
348
+ };
349
+ type DottedKeys<T> = (T extends ObjectType ? {
350
+ [K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
351
+ }[keyof T & string] : string) & string;
352
+ type OmitFromObject<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType ? {
353
+ [P in keyof T]: P extends Key ? OmitFromObject<T[Key], Rest> : T[P];
354
+ } : T : T : Omit<T, K>;
355
+ function omit<T extends Record<string, any>, K extends readonly DottedKeys<T>[]>(obj: T, keys: K): OmitFromObject<T, K[number]>;
356
+ export { omit, omit as default };
357
+ }
345
358
  declare module "object/index" {
346
359
  import { define } from "object/define";
347
360
  import { isObject } from "object/is";
348
361
  import { isNotEmptyObject } from "object/isNotEmpty";
349
362
  import { merge } from "object/merge";
350
363
  import { pick } from "object/pick";
351
- export { define, isObject, isObject as is, isNotEmptyObject, isNotEmptyObject as isNotEmpty, isNotEmptyObject as isNeObject, isNotEmptyObject as isNe, merge, pick };
364
+ import { omit } from "object/omit";
365
+ export { define, isObject, isObject as is, isNotEmptyObject, isNotEmptyObject as isNotEmpty, isNotEmptyObject as isNeObject, isNotEmptyObject as isNe, merge, pick, omit };
352
366
  }
353
367
  declare module "number/is" {
354
368
  function isNumber(val: unknown): val is number;
package/object/index.d.ts CHANGED
@@ -3,4 +3,5 @@ import { isObject } from './is';
3
3
  import { isNotEmptyObject } from './isNotEmpty';
4
4
  import { merge } from './merge';
5
5
  import { pick } from './pick';
6
- export { define, isObject, isObject as is, isNotEmptyObject, isNotEmptyObject as isNotEmpty, isNotEmptyObject as isNeObject, isNotEmptyObject as isNe, merge, pick };
6
+ import { omit } from './omit';
7
+ export { define, isObject, isObject as is, isNotEmptyObject, isNotEmptyObject as isNotEmpty, isNotEmptyObject as isNeObject, isNotEmptyObject as isNe, merge, pick, omit };
package/object/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pick = exports.merge = exports.isNe = exports.isNeObject = exports.isNotEmpty = exports.isNotEmptyObject = exports.is = exports.isObject = exports.define = void 0;
3
+ exports.omit = exports.pick = exports.merge = exports.isNe = exports.isNeObject = exports.isNotEmpty = exports.isNotEmptyObject = exports.is = exports.isObject = exports.define = void 0;
4
4
  const define_1 = require("./define");
5
5
  Object.defineProperty(exports, "define", { enumerable: true, get: function () { return define_1.define; } });
6
6
  const is_1 = require("./is");
@@ -15,3 +15,5 @@ const merge_1 = require("./merge");
15
15
  Object.defineProperty(exports, "merge", { enumerable: true, get: function () { return merge_1.merge; } });
16
16
  const pick_1 = require("./pick");
17
17
  Object.defineProperty(exports, "pick", { enumerable: true, get: function () { return pick_1.pick; } });
18
+ const omit_1 = require("./omit");
19
+ Object.defineProperty(exports, "omit", { enumerable: true, get: function () { return omit_1.omit; } });
@@ -0,0 +1,17 @@
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 ? {
8
+ [P in keyof T]: P extends Key ? OmitFromObject<T[Key], Rest> : T[P];
9
+ } : T : T : Omit<T, K>;
10
+ /**
11
+ * Returns a new object with the keys omitted from the passed object, handling nested keys recursively
12
+ *
13
+ * @param {Record<string, any>} obj - Object to omit from
14
+ * @param {string[]} keys - Array of keys to omit from object
15
+ */
16
+ declare function omit<T extends Record<string, any>, K extends readonly DottedKeys<T>[]>(obj: T, keys: K): OmitFromObject<T, K[number]>;
17
+ export { omit, omit as default };
package/object/omit.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.omit = omit;
4
+ exports.default = omit;
5
+ function innerOmit(obj, keys) {
6
+ const result = { ...obj };
7
+ const groups = {};
8
+ for (let i = 0; i < keys.length; i++) {
9
+ const key = keys[i];
10
+ if (typeof key !== 'string')
11
+ continue;
12
+ const [root, path] = key.trim().split('.', 2);
13
+ if (path) {
14
+ if (!groups[root])
15
+ groups[root] = [];
16
+ groups[root].push(path);
17
+ }
18
+ else {
19
+ delete result[root];
20
+ }
21
+ }
22
+ for (const root in groups) {
23
+ if (typeof result[root] !== 'object' || result[root] === null)
24
+ continue;
25
+ result[root] = innerOmit(result[root], groups[root]);
26
+ }
27
+ return result;
28
+ }
29
+ function omit(obj, keys) {
30
+ if (Object.prototype.toString.call(obj) !== '[object Object]' ||
31
+ !Array.isArray(keys) ||
32
+ !keys.length)
33
+ throw new TypeError('Please pass an object to omit from and a keys array');
34
+ return innerOmit(obj, keys);
35
+ }
package/object/pick.d.ts CHANGED
@@ -13,8 +13,8 @@ type UnionToIntersection<U> = (U extends any ? (k: U) => void : object) extends
13
13
  /**
14
14
  * Returns a new object with the keys picked from the passed object
15
15
  *
16
- * @param obj - Object to pick from
17
- * @param keys - Array of keys to pick from object
16
+ * @param {Record<string, any>} obj - Object to pick from
17
+ * @param {string[]} keys - Array of keys to pick from object
18
18
  */
19
19
  declare function pick<T extends Record<string, any>, K extends readonly DottedKeys<T>[]>(obj: T, keys: K): UnionToIntersection<PickFromObject<T, K[number]>>;
20
20
  export { pick, pick as default };
package/package.json CHANGED
@@ -1 +1 @@
1
- { "name": "@valkyriestudios/utils", "version": "12.25.1", "description": "A collection of single-function utilities for common tasks", "author": { "name": "Peter Vermeulen", "url": "https://www.linkedin.com/in/petervermeulen1/" }, "keywords": [ "utility", "library", "javascript", "js", "node", "bun" ], "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/ValkyrieStudios/utils.git" }, "bugs": { "url": "https://github.com/ValkyrieStudios/utils/issues" }, "homepage": "https://github.com/ValkyrieStudios/utils#readme", "types": "index.d.ts" }
1
+ { "name": "@valkyriestudios/utils", "version": "12.27.0", "description": "A collection of single-function utilities for common tasks", "author": { "name": "Peter Vermeulen", "url": "https://www.linkedin.com/in/petervermeulen1/" }, "keywords": [ "utility", "library", "javascript", "js", "node", "bun" ], "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/ValkyrieStudios/utils.git" }, "bugs": { "url": "https://github.com/ValkyrieStudios/utils/issues" }, "homepage": "https://github.com/ValkyrieStudios/utils#readme", "types": "index.d.ts" }