xypriss 9.12.49 → 9.12.52

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.
@@ -1,466 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var xyprissSecurity = require('xypriss-security');
4
+ var ObjectWrapper = require('./ObjectWrapper.js');
4
5
 
5
- // ---------------------------------------------------------------------------
6
- class ObjectWrapper {
7
- constructor(obj) {
8
- this.current = obj;
9
- }
10
- /**
11
- * **value**
12
- *
13
- * Unwraps and returns the underlying plain object held by this wrapper.
14
- * Call this at the end of a chain to get back a normal object.
15
- *
16
- * @returns The current wrapped object.
17
- *
18
- * @example
19
- * ```ts
20
- * const obj = __sys__.utils.obj.of({ a: 1 });
21
- * obj.value(); // { a: 1 }
22
- * ```
23
- */
24
- value() {
25
- return this.current;
26
- }
27
- /**
28
- * **raw**
29
- *
30
- * Alias for {@link value}. Useful when `value` reads awkwardly in context.
31
- *
32
- * @returns The current wrapped object.
33
- */
34
- raw() {
35
- return this.current;
36
- }
37
- /**
38
- * **clone**
39
- *
40
- * Deep-clones the wrapped object (via `XStringify`) and continues
41
- * the chain on the cloned copy, leaving the original untouched.
42
- *
43
- * @returns `this`, now wrapping a deep copy of the previous value.
44
- *
45
- * @example
46
- * ```ts
47
- * const source = { nested: { count: 1 } };
48
- * const obj = __sys__.utils.obj.of(source).clone();
49
- * obj.value().nested.count = 99;
50
- * // source.nested.count is still 1
51
- * ```
52
- */
53
- clone() {
54
- this.current = JSON.parse(xyprissSecurity.XStringify(this.current));
55
- return this;
56
- }
57
- /**
58
- * **pick**
59
- *
60
- * Narrows the wrapped object down to only the given keys.
61
- *
62
- * @param keys - The keys to keep.
63
- * @returns `this`, now wrapping only the picked keys.
64
- *
65
- * @example
66
- * ```ts
67
- * __sys__.utils.obj.of({ a: 1, b: 2, c: 3 }).pick(["a", "c"]).value();
68
- * // { a: 1, c: 3 }
69
- * ```
70
- */
71
- pick(keys) {
72
- const result = keys.reduce((acc, key) => {
73
- if (key in this.current)
74
- acc[key] = this.current[key];
75
- return acc;
76
- }, {});
77
- return new ObjectWrapper(result);
78
- }
79
- /**
80
- * **deepPick**
81
- *
82
- * Extracts a subset of the wrapped object using dot-notation paths,
83
- * preserving the original nested structure. Paths that do not exist
84
- * in the object are silently ignored.
85
- *
86
- * @param paths - Dot-notation paths to extract (e.g. `"a.b.c"`).
87
- * @param separator - Path separator (default: `"."`)
88
- * @returns A new wrapper around the extracted nested object.
89
- *
90
- * @example
91
- * ```ts
92
- * const data = {
93
- * user: { name: "Alice", age: 30, password: "secret" },
94
- * meta: { created: "2024-01-01", version: 2 },
95
- * };
96
- *
97
- * __sys__.utils.obj
98
- * .of(data)
99
- * .deepPick(["user.name", "user.age", "meta.version"])
100
- * .value();
101
- * // { user: { name: "Alice", age: 30 }, meta: { version: 2 } }
102
- * ```
103
- */
104
- deepPick(paths, separator) {
105
- const sep = separator ?? ".";
106
- const result = {};
107
- for (const path of paths) {
108
- const parts = path.split(sep);
109
- let src = this.current;
110
- let dst = result;
111
- for (let i = 0; i < parts.length; i++) {
112
- const part = parts[i];
113
- if (src === null || src === undefined || !(part in src)) {
114
- break;
115
- }
116
- if (i === parts.length - 1) {
117
- dst[part] = src[part];
118
- }
119
- else {
120
- if (typeof dst[part] !== "object" ||
121
- dst[part] === null ||
122
- Array.isArray(dst[part])) {
123
- dst[part] = {};
124
- }
125
- dst = dst[part];
126
- src = src[part];
127
- }
128
- }
129
- }
130
- return new ObjectWrapper(result);
131
- }
132
- /**
133
- * **omit**
134
- *
135
- * Removes the given keys from the wrapped object.
136
- *
137
- * @param keys - The keys to remove.
138
- * @returns `this`, now wrapping the object without those keys.
139
- *
140
- * @example
141
- * ```ts
142
- * __sys__.utils.obj.of({ a: 1, b: 2, c: 3 }).omit(["b"]).value();
143
- * // { a: 1, c: 3 }
144
- * ```
145
- */
146
- omit(keys) {
147
- const result = { ...this.current };
148
- keys.forEach((key) => delete result[key]);
149
- return new ObjectWrapper(result);
150
- }
151
- /**
152
- * **isEmpty**
153
- *
154
- * Checks whether the wrapped object has no own enumerable keys.
155
- * This is a terminal read (does not return the wrapper), since it
156
- * yields a boolean rather than an object.
157
- *
158
- * @returns `true` if the object has no own keys.
159
- *
160
- * @example
161
- * ```ts
162
- * __sys__.utils.obj.of({}).isEmpty(); // true
163
- * ```
164
- */
165
- isEmpty() {
166
- return Object.keys(this.current).length === 0;
167
- }
168
- /**
169
- * **flatten**
170
- *
171
- * Collapses the wrapped object's nested structure into flat
172
- * dot-notation (or custom separator) keys.
173
- *
174
- * @param separator - Path separator (default: `"."`).
175
- * @returns A new wrapper around the flattened object.
176
- *
177
- * @example
178
- * ```ts
179
- * __sys__.utils.obj.of({ a: { b: 1 } }).flatten().value();
180
- * // { "a.b": 1 }
181
- * ```
182
- */
183
- flatten(separator = ".") {
184
- const result = {};
185
- const recurse = (current, path = "") => {
186
- for (const [key, val] of Object.entries(current)) {
187
- const newPath = path ? `${path}${separator}${key}` : key;
188
- if (val &&
189
- typeof val === "object" &&
190
- !Array.isArray(val) &&
191
- Object.keys(val).length > 0) {
192
- recurse(val, newPath);
193
- }
194
- else {
195
- result[newPath] = val;
196
- }
197
- }
198
- };
199
- recurse(this.current);
200
- return new ObjectWrapper(result);
201
- }
202
- /**
203
- * **unflatten**
204
- *
205
- * Reverses {@link flatten}, expanding dot-notation (or custom
206
- * separator) keys back into a nested object.
207
- *
208
- * @param separator - Path separator used in the flat keys (default: `"."`).
209
- * @returns A new wrapper around the nested object.
210
- *
211
- * @example
212
- * ```ts
213
- * __sys__.utils.obj.of({ "a.b": 1, "a.c": 2 }).unflatten().value();
214
- * // { a: { b: 1, c: 2 } }
215
- * ```
216
- */
217
- unflatten(separator = ".") {
218
- const result = {};
219
- for (const [flatKey, val] of Object.entries(this.current)) {
220
- const parts = flatKey.split(separator);
221
- let cursor = result;
222
- parts.forEach((part, i) => {
223
- if (i === parts.length - 1) {
224
- cursor[part] = val;
225
- }
226
- else {
227
- if (typeof cursor[part] !== "object" ||
228
- cursor[part] === null) {
229
- cursor[part] = {};
230
- }
231
- cursor = cursor[part];
232
- }
233
- });
234
- }
235
- return new ObjectWrapper(result);
236
- }
237
- /**
238
- * **merge**
239
- *
240
- * Deep-merges one or more source objects into the wrapped object.
241
- * Plain object values are merged recursively; arrays and primitives
242
- * are overwritten by the last source that defines them.
243
- *
244
- * @param sources - One or more partial objects to merge in.
245
- * @returns `this`, now wrapping the merged result.
246
- *
247
- * @example
248
- * ```ts
249
- * __sys__.utils.obj.of({ a: 1, nested: { x: 1 } })
250
- * .merge({ nested: { y: 2 } })
251
- * .value();
252
- * // { a: 1, nested: { x: 1, y: 2 } }
253
- * ```
254
- */
255
- merge(...sources) {
256
- const isPlainObject = (val) => !!val && typeof val === "object" && !Array.isArray(val);
257
- const deepMerge = (target, source) => {
258
- for (const key of Object.keys(source)) {
259
- if (isPlainObject(source[key]) && isPlainObject(target[key])) {
260
- deepMerge(target[key], source[key]);
261
- }
262
- else {
263
- target[key] = source[key];
264
- }
265
- }
266
- return target;
267
- };
268
- this.current = sources.reduce((acc, src) => deepMerge(acc, src), this.current);
269
- return this;
270
- }
271
- /**
272
- * **mapValues**
273
- *
274
- * Transforms every value of the wrapped object using `fn`, keeping
275
- * the same keys.
276
- *
277
- * @param fn - Mapping function receiving `(value, key)`.
278
- * @returns A new wrapper around the transformed object.
279
- *
280
- * @example
281
- * ```ts
282
- * __sys__.utils.obj.of({ a: 1, b: 2 }).mapValues((v) => v * 10).value();
283
- * // { a: 10, b: 20 }
284
- * ```
285
- */
286
- mapValues(fn) {
287
- const result = {};
288
- for (const key of Object.keys(this.current)) {
289
- result[key] = fn(this.current[key], key);
290
- }
291
- return new ObjectWrapper(result);
292
- }
293
- /**
294
- * **mapKeys**
295
- *
296
- * Transforms every key of the wrapped object using `fn`, keeping
297
- * the same values.
298
- *
299
- * @param fn - Mapping function receiving `(key, value)`. Must return a string.
300
- * @returns A new wrapper around the object with renamed keys.
301
- *
302
- * @example
303
- * ```ts
304
- * __sys__.utils.obj.of({ a: 1, b: 2 })
305
- * .mapKeys((k) => k.toUpperCase())
306
- * .value();
307
- * // { A: 1, B: 2 }
308
- * ```
309
- */
310
- mapKeys(fn) {
311
- const result = {};
312
- for (const key of Object.keys(this.current)) {
313
- result[fn(key, this.current[key])] = this.current[key];
314
- }
315
- return new ObjectWrapper(result);
316
- }
317
- /**
318
- * **filter**
319
- *
320
- * Keeps only the key-value pairs for which `predicate` returns `true`.
321
- *
322
- * @param predicate - Function receiving `(value, key)`.
323
- * @returns A new wrapper around the filtered object.
324
- *
325
- * @example
326
- * ```ts
327
- * __sys__.utils.obj.of({ a: 1, b: 2, c: 3 })
328
- * .filter((v) => v > 1)
329
- * .value();
330
- * // { b: 2, c: 3 }
331
- * ```
332
- */
333
- filter(predicate) {
334
- const result = {};
335
- for (const key of Object.keys(this.current)) {
336
- if (predicate(this.current[key], key)) {
337
- result[key] = this.current[key];
338
- }
339
- }
340
- return new ObjectWrapper(result);
341
- }
342
- /**
343
- * **keys**
344
- *
345
- * Returns the own enumerable keys of the wrapped object.
346
- * This is a terminal read.
347
- *
348
- * @returns Array of keys.
349
- */
350
- keys() {
351
- return Object.keys(this.current);
352
- }
353
- /**
354
- * **values**
355
- *
356
- * Returns the own enumerable values of the wrapped object.
357
- * This is a terminal read.
358
- *
359
- * @returns Array of values.
360
- */
361
- values() {
362
- return Object.values(this.current);
363
- }
364
- /**
365
- * **entries**
366
- *
367
- * Returns the own enumerable `[key, value]` pairs of the wrapped object.
368
- * This is a terminal read.
369
- *
370
- * @returns Array of `[key, value]` tuples.
371
- */
372
- entries() {
373
- return Object.entries(this.current);
374
- }
375
- /**
376
- * **has**
377
- *
378
- * Checks whether the wrapped object has the given own key.
379
- * This is a terminal read.
380
- *
381
- * @param key - The key to check.
382
- * @returns `true` if the key exists on the object.
383
- */
384
- has(key) {
385
- return Object.prototype.hasOwnProperty.call(this.current, key);
386
- }
387
- /**
388
- * **get**
389
- *
390
- * Safely reads a possibly-nested value using dot-notation path,
391
- * returning `fallback` if any part of the path is missing.
392
- * This is a terminal read.
393
- *
394
- * @param path - Dot-notation path (e.g. `"a.b.c"`).
395
- * @param fallback - Value returned if the path can't be resolved.
396
- * @returns The resolved value or the fallback.
397
- *
398
- * @example
399
- * ```ts
400
- * __sys__.utils.obj.of({ a: { b: { c: 42 } } }).get("a.b.c"); // 42
401
- * __sys__.utils.obj.of({ a: {} }).get("a.b.c", "missing"); // "missing"
402
- * ```
403
- */
404
- get(path, fallback = undefined) {
405
- const parts = path.split(".");
406
- let cursor = this.current;
407
- for (const part of parts) {
408
- if (cursor === null || cursor === undefined)
409
- return fallback;
410
- cursor = cursor[part];
411
- }
412
- return cursor === undefined ? fallback : cursor;
413
- }
414
- /**
415
- * **set**
416
- *
417
- * Sets a possibly-nested value using dot-notation path, creating
418
- * intermediate objects as needed.
419
- *
420
- * @param path - Dot-notation path (e.g. `"a.b.c"`).
421
- * @param value - The value to set.
422
- * @returns `this`, with the value set at the given path.
423
- *
424
- * @example
425
- * ```ts
426
- * __sys__.utils.obj.of<any>({}).set("a.b.c", 42).value();
427
- * // { a: { b: { c: 42 } } }
428
- * ```
429
- */
430
- set(path, value) {
431
- const parts = path.split(".");
432
- let cursor = this.current;
433
- parts.forEach((part, i) => {
434
- if (i === parts.length - 1) {
435
- cursor[part] = value;
436
- }
437
- else {
438
- if (typeof cursor[part] !== "object" || cursor[part] === null) {
439
- cursor[part] = {};
440
- }
441
- cursor = cursor[part];
442
- }
443
- });
444
- return this;
445
- }
446
- /**
447
- * **equals**
448
- *
449
- * Performs a deep structural equality check between the wrapped
450
- * object and `other`. This is a terminal read.
451
- *
452
- * @param other - The object to compare against.
453
- * @returns `true` if both objects are deeply equal.
454
- *
455
- * @example
456
- * ```ts
457
- * __sys__.utils.obj.of({ a: { b: 1 } }).equals({ a: { b: 1 } }); // true
458
- * ```
459
- */
460
- equals(other) {
461
- return __sys__.utils.obj.deepEqual(this.current, other);
462
- }
463
- }
464
6
  /**
465
7
  * **ObjectUtils — XyPriss Object Utilities**
466
8
  *
@@ -504,7 +46,7 @@ class ObjectUtils {
504
46
  * ```
505
47
  */
506
48
  static of(obj) {
507
- return new ObjectWrapper(obj);
49
+ return new ObjectWrapper.ObjectWrapper(obj);
508
50
  }
509
51
  /**
510
52
  * **of** (instance method)
@@ -629,6 +171,150 @@ class ObjectUtils {
629
171
  isEmpty(obj) {
630
172
  return Object.keys(obj).length === 0;
631
173
  }
174
+ /**
175
+ * **Check if an Object has Any Empty Values**
176
+ *
177
+ * Returns `true` if at least one property value in the object is `undefined`, `null`,
178
+ * an empty string `""` (or whitespace-only if trim: true), empty array `[]`, or empty object `{}`.
179
+ *
180
+ * @param obj - The object to inspect.
181
+ * @param keys - Optional specific keys to check.
182
+ * @param options - Optional configuration (e.g. `trim: boolean`).
183
+ * @returns `true` if at least one value is empty/undefined.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * utils.hasEmpty({ name: "Alice", phone: undefined }); // true
188
+ * utils.hasEmpty({ name: "Alice", phone: "+22501020304" }); // false
189
+ * ```
190
+ */
191
+ hasEmpty(obj, keys, options = { trim: true }) {
192
+ return new ObjectWrapper.ObjectWrapper(obj).hasEmpty(keys, options);
193
+ }
194
+ /**
195
+ * **hasAnyEmpty**
196
+ *
197
+ * Alias for {@link hasEmpty}. Returns `true` if at least one property is empty.
198
+ */
199
+ hasAnyEmpty(obj, keys, options) {
200
+ return this.hasEmpty(obj, keys, options);
201
+ }
202
+ /**
203
+ * **Check if All Object Values are Empty**
204
+ *
205
+ * Returns `true` if ALL property values in the object are `undefined`, `null`,
206
+ * empty string `""`, empty array `[]`, or empty object `{}` (or if the object has 0 keys).
207
+ *
208
+ * @param obj - The object to inspect.
209
+ * @param keys - Optional specific keys to check.
210
+ * @param options - Optional configuration (e.g. `trim: boolean`).
211
+ * @returns `true` if all values are empty.
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * utils.isAllEmpty({ name: undefined, phone: "", email: null }); // true
216
+ * utils.isAllEmpty({ name: "Alice", phone: "" }); // false
217
+ * ```
218
+ */
219
+ isAllEmpty(obj, keys, options = { trim: true }) {
220
+ return new ObjectWrapper.ObjectWrapper(obj).isAllEmpty(keys, options);
221
+ }
222
+ /**
223
+ * **Check if an Object has Any Filled/Non-Empty Values**
224
+ *
225
+ * Returns `true` if AT LEAST ONE property value in the object is present and non-empty
226
+ * (not `undefined`, not `null`, not `""` empty string, not empty `[]`, and not empty `{}`).
227
+ *
228
+ * This is the exact inverse of {@link isAllEmpty}.
229
+ *
230
+ * @param obj - The object to inspect.
231
+ * @param keys - Optional specific keys to check.
232
+ * @param options - Optional configuration (e.g. `trim: boolean`).
233
+ * @returns `true` if at least one value is non-empty.
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * utils.hasAny({ name: undefined, phone: "+22501020304" }); // true
238
+ * utils.hasAny({ name: undefined, phone: "", email: null }); // false
239
+ * ```
240
+ */
241
+ hasAny(obj, keys, options = { trim: true }) {
242
+ return new ObjectWrapper.ObjectWrapper(obj).hasAny(keys, options);
243
+ }
244
+ /**
245
+ * **hasAnyValue**
246
+ *
247
+ * Alias for {@link hasAny}. Returns `true` if at least one property is non-empty.
248
+ */
249
+ hasAnyValue(obj, keys, options) {
250
+ return this.hasAny(obj, keys, options);
251
+ }
252
+ /**
253
+ * **Check if an Object contains Non-Null Values**
254
+ *
255
+ * Returns `true` if AT LEAST ONE property value in the object is not `null` and not `undefined`.
256
+ *
257
+ * @param obj - The object to inspect.
258
+ * @param keys - Optional specific keys to check.
259
+ * @returns `true` if at least one value is not null and not undefined.
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * utils.hasNonNull({ a: undefined, b: null, c: "" }); // true (c is "")
264
+ * utils.hasNonNull({ a: undefined, b: null }); // false
265
+ * ```
266
+ */
267
+ hasNonNull(obj, keys) {
268
+ return new ObjectWrapper.ObjectWrapper(obj).hasNonNull(keys);
269
+ }
270
+ /**
271
+ * **Check if All Properties in an Object are Non-Null**
272
+ *
273
+ * Returns `true` if ALL property values in the object are not `null` and not `undefined`.
274
+ *
275
+ * @param obj - The object to inspect.
276
+ * @param keys - Optional specific keys to check.
277
+ * @returns `true` if all values are not null and not undefined.
278
+ */
279
+ isAllNonNull(obj, keys) {
280
+ return new ObjectWrapper.ObjectWrapper(obj).isAllNonNull(keys);
281
+ }
282
+ /**
283
+ * **Check if an Object contains Undefined Values**
284
+ *
285
+ * Returns `true` if at least one property value in the object is strictly `undefined`.
286
+ *
287
+ * @param obj - The object to inspect.
288
+ * @param keys - Optional specific keys to check.
289
+ * @returns `true` if at least one value is undefined.
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * utils.hasUndefined({ name: "Alice", phone: undefined }); // true
294
+ * utils.hasUndefined({ name: "Alice", phone: null }); // false
295
+ * ```
296
+ */
297
+ hasUndefined(obj, keys) {
298
+ return new ObjectWrapper.ObjectWrapper(obj).hasUndefined(keys);
299
+ }
300
+ /**
301
+ * **Compact Object**
302
+ *
303
+ * Returns a new plain object with all `undefined`, `null`, and empty string properties removed.
304
+ *
305
+ * @param obj - The object to clean.
306
+ * @param options - Optional configuration (e.g. `trim: boolean`).
307
+ * @returns A new cleaned object without empty properties.
308
+ *
309
+ * @example
310
+ * ```ts
311
+ * utils.compact({ name: "Alice", phone: undefined, email: "" });
312
+ * // { name: "Alice" }
313
+ * ```
314
+ */
315
+ compact(obj, options = { trim: true }) {
316
+ return new ObjectWrapper.ObjectWrapper(obj).compact(options).value();
317
+ }
632
318
  /**
633
319
  * **flattenObject**
634
320
  *
@@ -1012,31 +698,6 @@ class ObjectUtils {
1012
698
  }
1013
699
  return result;
1014
700
  }
1015
- /**
1016
- * **compact**
1017
- *
1018
- * Returns a new object with all keys whose value is `null` or
1019
- * `undefined` removed.
1020
- *
1021
- * @param obj - The source object.
1022
- * @returns A new object without null/undefined values.
1023
- *
1024
- * @example
1025
- * ```ts
1026
- * utils.compact({ a: 1, b: null, c: undefined, d: 0 });
1027
- * // { a: 1, d: 0 }
1028
- * ```
1029
- */
1030
- compact(obj) {
1031
- const result = {};
1032
- for (const key of Object.keys(obj)) {
1033
- const val = obj[key];
1034
- if (val !== null && val !== undefined) {
1035
- result[key] = val;
1036
- }
1037
- }
1038
- return result;
1039
- }
1040
701
  /**
1041
702
  * **isPlainObject**
1042
703
  *
@@ -1064,5 +725,4 @@ class ObjectUtils {
1064
725
  }
1065
726
 
1066
727
  exports.ObjectUtils = ObjectUtils;
1067
- exports.ObjectWrapper = ObjectWrapper;
1068
728
  //# sourceMappingURL=ObjectUtils.js.map