@terzogenito/json-utils 1.0.12 → 1.0.13

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.
Files changed (4) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +438 -438
  3. package/index.js +803 -669
  4. package/package.json +35 -35
package/index.js CHANGED
@@ -1,669 +1,803 @@
1
- const fs = require('fs');
2
- const https = require('https');
3
-
4
- function getString(filePath) {
5
- return fs.readFileSync(filePath, 'utf-8');
6
- }
7
-
8
- function getFile(filePath, callback) {
9
- fs.readFile(filePath, 'utf8', (err, data) => {
10
- if (err) {
11
- return;
12
- } else {
13
- callback(data);
14
- }
15
- });
16
- }
17
-
18
- function loadFile(filePath) {
19
- return new Promise((resolve, reject) => {
20
- fs.readFile(filePath, 'utf8', (err, data) => {
21
- if (err) {
22
- reject(err);
23
- } else {
24
- resolve(data);
25
- }
26
- });
27
- });
28
- }
29
-
30
- async function getData(filePath) {
31
- try {
32
- const data = await loadFile(filePath);
33
- return data;
34
- } catch {
35
- return null;
36
- }
37
- }
38
-
39
- function getURL(url, callback) {
40
- https.get(url, (response) => {
41
- let data = '';
42
- response.on('data', chunk => {
43
- data += chunk;
44
- });
45
- response.on('end', () => {
46
- callback(data || null);
47
- });
48
- }).on('error', (err) => {
49
- callback(null);
50
- });
51
- }
52
-
53
- function isUrl(input) {
54
- const urlPattern = /^(https?:\/\/|ftp:\/\/|www\.)/i;
55
- return urlPattern.test(input);
56
- }
57
-
58
- function getContent(target, callback) {
59
- if (isUrl(target)) {
60
- getURL(target, callback);
61
- } else {
62
- getFile(target, callback);
63
- }
64
- }
65
-
66
- function readJSON(jsonString) {
67
- return JSON.parse(jsonString);
68
- }
69
-
70
- function toString(jsonObject) {
71
- return JSON.stringify(jsonObject);
72
- }
73
-
74
- function isValid(jsonString) {
75
- try {
76
- JSON.parse(jsonString);
77
- return true;
78
- } catch {
79
- return false;
80
- }
81
- }
82
-
83
- function isJSON(jsonObject) {
84
- try {
85
- const parsedData = JSON.parse(jsonObject);
86
- return typeof parsedData === 'object' && parsedData !== null;
87
- } catch (error) {
88
- return false;
89
- }
90
- }
91
-
92
- function isJSONObject(jsonObject) {
93
- try {
94
- return typeof jsonObject === 'object' && jsonObject !== null && jsonObject !== undefined;
95
- } catch (error) {
96
- return false;
97
- }
98
- }
99
-
100
- function getJSON(target, callback) {
101
- getContent(target, data => {
102
- if (!data) {
103
- return callback(null);
104
- }
105
- if (!isValid(data)) {
106
- return callback(null);
107
- }
108
- try {
109
- callback(readJSON(data));
110
- } catch {
111
- callback(null);
112
- }
113
- });
114
- }
115
-
116
- function beautifyJSON(jsonString, indent = 2) {
117
- try {
118
- if (typeof jsonString !== 'string') return null;
119
- const jsonObject = JSON.parse(jsonString);
120
- return JSON.stringify(jsonObject, null, indent);
121
- } catch {
122
- return null;
123
- }
124
- }
125
-
126
- function beautify(jsonObject, indent) {
127
- try {
128
- if (!indent) indent = 2;
129
- return JSON.stringify(jsonObject, null, indent);
130
- } catch (error) {
131
- return null;
132
- }
133
- }
134
-
135
- function getAttributes(jsonObject) {
136
- try {
137
- if (typeof jsonObject === 'string') {
138
- jsonObject = JSON.parse(jsonObject);
139
- }
140
-
141
- if (typeof jsonObject !== 'object' || jsonObject === null) {
142
- return [];
143
- }
144
-
145
- return Object.keys(jsonObject);
146
- } catch (error) {
147
- return [];
148
- }
149
- }
150
-
151
- function getMeta(jsonObject) {
152
- try {
153
- if (typeof jsonObject === 'string') {
154
- jsonObject = JSON.parse(jsonObject);
155
- }
156
-
157
- if (typeof jsonObject !== 'object' || jsonObject === null) {
158
- return {};
159
- }
160
-
161
- const meta = {};
162
-
163
- for (const [key, value] of Object.entries(jsonObject)) {
164
- let type = typeof value;
165
-
166
- if (type === 'object') {
167
- if (value === null) {
168
- type = 'null';
169
- } else if (Array.isArray(value)) {
170
- type = 'array';
171
- } else if (value instanceof Date) {
172
- type = 'date';
173
- } else {
174
- type = 'object';
175
- }
176
- } else if (type === 'number') {
177
- type = Number.isInteger(value) ? 'integer' : 'float';
178
- }
179
-
180
- meta[key] = type;
181
- }
182
-
183
- return meta;
184
- } catch (error) {
185
- return {};
186
- }
187
- }
188
-
189
- function getMetaDetail(jsonObject) {
190
- try {
191
- if (typeof jsonObject === 'string') {
192
- jsonObject = JSON.parse(jsonObject);
193
- }
194
-
195
- if (typeof jsonObject !== 'object' || jsonObject === null) {
196
- return {};
197
- }
198
-
199
- function getNestedMeta(obj, path = '') {
200
- const meta = {};
201
-
202
- for (const [key, value] of Object.entries(obj)) {
203
- const currentPath = path ? `${path}.${key}` : key;
204
- const attributeMeta = {};
205
-
206
- let type = typeof value;
207
-
208
- if (value === null) {
209
- type = 'null';
210
- attributeMeta.type = type;
211
- attributeMeta.isRequired = false;
212
- attributeMeta.path = currentPath;
213
- } else if (Array.isArray(value)) {
214
- type = 'array';
215
- attributeMeta.type = type;
216
- attributeMeta.length = value.length;
217
- attributeMeta.isRequired = true;
218
- attributeMeta.path = currentPath;
219
-
220
- if (value.length > 0) {
221
- const firstElement = value[0];
222
- const elementType = typeof firstElement;
223
-
224
- if (elementType === 'object' && firstElement !== null) {
225
- if (Array.isArray(firstElement)) {
226
- attributeMeta.elementType = 'array';
227
- } else {
228
- attributeMeta.elementType = 'object';
229
- attributeMeta.children = getNestedMeta(firstElement, `${currentPath}[0]`);
230
- }
231
- } else {
232
- attributeMeta.elementType = elementType;
233
- }
234
- } else {
235
- attributeMeta.elementType = 'unknown';
236
- }
237
- } else if (value instanceof Date) {
238
- type = 'date';
239
- attributeMeta.type = type;
240
- attributeMeta.isRequired = true;
241
- attributeMeta.path = currentPath;
242
- } else if (type === 'object') {
243
- type = 'object';
244
- attributeMeta.type = type;
245
- attributeMeta.isRequired = true;
246
- attributeMeta.path = currentPath;
247
- attributeMeta.keysCount = Object.keys(value).length;
248
-
249
- attributeMeta.children = getNestedMeta(value, currentPath);
250
- } else {
251
- attributeMeta.type = type;
252
- attributeMeta.isRequired = true;
253
- attributeMeta.path = currentPath;
254
-
255
- if (type === 'number') {
256
- attributeMeta.numberType = Number.isInteger(value) ? 'integer' : 'float';
257
- }
258
- }
259
-
260
- meta[key] = attributeMeta;
261
- }
262
-
263
- return meta;
264
- }
265
-
266
- return getNestedMeta(jsonObject);
267
- } catch (error) {
268
- console.error('Error in getMetaDetail:', error);
269
- return {};
270
- }
271
- }
272
-
273
- function getMetaCompact(jsonObject) {
274
- try {
275
- if (typeof jsonObject === 'string') {
276
- jsonObject = JSON.parse(jsonObject);
277
- }
278
-
279
- if (typeof jsonObject !== 'object' || jsonObject === null) {
280
- return {};
281
- }
282
-
283
- function getCompactMeta(obj) {
284
- const meta = {};
285
-
286
- for (const [key, value] of Object.entries(obj)) {
287
- let type = typeof value;
288
-
289
- if (value === null) {
290
- meta[key] = 'null';
291
- } else if (Array.isArray(value)) {
292
- if (value.length > 0) {
293
- const firstElement = value[0];
294
- const elementType = typeof firstElement;
295
- if (elementType === 'object' && firstElement !== null) {
296
- meta[key] = `array[${Array.isArray(firstElement) ? 'array' : 'object'}]`;
297
- } else {
298
- meta[key] = `array[${elementType}]`;
299
- }
300
- } else {
301
- meta[key] = 'array[]';
302
- }
303
- } else if (value instanceof Date) {
304
- meta[key] = 'date';
305
- } else if (type === 'object') {
306
- meta[key] = getCompactMeta(value);
307
- } else if (type === 'number') {
308
- meta[key] = Number.isInteger(value) ? 'integer' : 'float';
309
- } else {
310
- meta[key] = type;
311
- }
312
- }
313
-
314
- return meta;
315
- }
316
-
317
- return getCompactMeta(jsonObject);
318
- } catch (error) {
319
- console.error('Error in getMetaCompact:', error);
320
- return {};
321
- }
322
- }
323
-
324
- function getPartial(jsonObject, attributes) {
325
- try {
326
- if (typeof jsonObject === 'string') {
327
- jsonObject = JSON.parse(jsonObject);
328
- }
329
-
330
- if (typeof jsonObject !== 'object' || jsonObject === null) {
331
- return {};
332
- }
333
-
334
- const result = {};
335
-
336
- if (Array.isArray(attributes)) {
337
- for (const attr of attributes) {
338
- if (attr in jsonObject) {
339
- result[attr] = jsonObject[attr];
340
- }
341
- }
342
- }
343
- else if (typeof attributes === 'string') {
344
- if (attributes in jsonObject) {
345
- result[attributes] = jsonObject[attributes];
346
- }
347
- }
348
- else if (typeof attributes === 'object' && attributes !== null) {
349
- for (const [newKey, originalKey] of Object.entries(attributes)) {
350
- if (originalKey in jsonObject) {
351
- result[newKey] = jsonObject[originalKey];
352
- }
353
- }
354
- }
355
-
356
- return result;
357
- } catch (error) {
358
- console.error('Error in getPartial:', error);
359
- return {};
360
- }
361
- }
362
-
363
- function getPartialDeep(jsonObject, attributePaths) {
364
- try {
365
- if (typeof jsonObject === 'string') {
366
- jsonObject = JSON.parse(jsonObject);
367
- }
368
-
369
- if (typeof jsonObject !== 'object' || jsonObject === null) {
370
- return {};
371
- }
372
-
373
- const result = {};
374
-
375
- function getValueFromPath(obj, path) {
376
- const parts = path.split('.');
377
- let current = obj;
378
-
379
- for (const part of parts) {
380
- if (current && typeof current === 'object' && part in current) {
381
- current = current[part];
382
- } else {
383
- return undefined;
384
- }
385
- }
386
-
387
- return current;
388
- }
389
-
390
- if (Array.isArray(attributePaths)) {
391
- for (const path of attributePaths) {
392
- const value = getValueFromPath(jsonObject, path);
393
- if (value !== undefined) {
394
- const key = path.split('.').pop();
395
- result[key] = value;
396
- }
397
- }
398
- }
399
- else if (typeof attributePaths === 'object' && attributePaths !== null) {
400
- for (const [newKey, path] of Object.entries(attributePaths)) {
401
- const value = getValueFromPath(jsonObject, path);
402
- if (value !== undefined) {
403
- result[newKey] = value;
404
- }
405
- }
406
- }
407
-
408
- return result;
409
- } catch (error) {
410
- console.error('Error in getPartialDeep:', error);
411
- return {};
412
- }
413
- }
414
-
415
- function getPartialWithDefaults(jsonObject, attributesConfig) {
416
- try {
417
- if (typeof jsonObject === 'string') {
418
- jsonObject = JSON.parse(jsonObject);
419
- }
420
-
421
- if (typeof jsonObject !== 'object' || jsonObject === null) {
422
- return {};
423
- }
424
-
425
- const result = {};
426
-
427
- function getValueFromPath(obj, path, defaultValue) {
428
- const parts = path.split('.');
429
- let current = obj;
430
-
431
- for (const part of parts) {
432
- if (current && typeof current === 'object' && part in current) {
433
- current = current[part];
434
- } else {
435
- return defaultValue;
436
- }
437
- }
438
-
439
- return current;
440
- }
441
-
442
- for (const [outputKey, config] of Object.entries(attributesConfig)) {
443
- if (typeof config === 'string') {
444
- result[outputKey] = getValueFromPath(jsonObject, config, undefined);
445
- } else if (typeof config === 'object' && config !== null) {
446
- const path = config.path || outputKey;
447
- const defaultValue = config.default;
448
- let value = getValueFromPath(jsonObject, path, defaultValue);
449
-
450
- if (config.transform && typeof config.transform === 'function') {
451
- value = config.transform(value);
452
- }
453
-
454
- result[outputKey] = value;
455
- }
456
- }
457
-
458
- return result;
459
- } catch (error) {
460
- console.error('Error in getPartialWithDefaults:', error);
461
- return {};
462
- }
463
- }
464
-
465
- function excludeAttributes(jsonObject, attributesToExclude) {
466
- try {
467
- if (typeof jsonObject === 'string') {
468
- jsonObject = JSON.parse(jsonObject);
469
- }
470
-
471
- if (typeof jsonObject !== 'object' || jsonObject === null) {
472
- return {};
473
- }
474
-
475
- const result = { ...jsonObject };
476
-
477
- if (Array.isArray(attributesToExclude)) {
478
- for (const attr of attributesToExclude) {
479
- delete result[attr];
480
- }
481
- }
482
- else if (typeof attributesToExclude === 'string') {
483
- delete result[attributesToExclude];
484
- }
485
-
486
- return result;
487
- } catch (error) {
488
- console.error('Error in excludeAttributes:', error);
489
- return {};
490
- }
491
- }
492
-
493
- function getSize(jsonObject) {
494
- try {
495
- const jsonString = typeof jsonObject === 'string'
496
- ? jsonObject
497
- : JSON.stringify(jsonObject);
498
- return new Blob([jsonString]).size;
499
- } catch (error) {
500
- console.error('Error in getSize:', error);
501
- return 0;
502
- }
503
- }
504
-
505
- function sortBy(array, key, ascending = true) {
506
- try {
507
- if (!Array.isArray(array)) return array;
508
-
509
- return [...array].sort((a, b) => {
510
- const aValue = typeof key === 'function' ? key(a) : a[key];
511
- const bValue = typeof key === 'function' ? key(b) : b[key];
512
-
513
- if (aValue < bValue) return ascending ? -1 : 1;
514
- if (aValue > bValue) return ascending ? 1 : -1;
515
- return 0;
516
- });
517
- } catch (error) {
518
- console.error('Error in sortBy:', error);
519
- return array;
520
- }
521
- }
522
-
523
- function findKeys(jsonObject, keyName) {
524
- try {
525
- if (typeof jsonObject === 'string') {
526
- jsonObject = JSON.parse(jsonObject);
527
- }
528
-
529
- if (typeof jsonObject !== 'object' || jsonObject === null) {
530
- return [];
531
- }
532
-
533
- const results = [];
534
- const pattern = keyName.includes('*')
535
- ? new RegExp('^' + keyName.replace(/\*/g, '.*') + '$')
536
- : null;
537
-
538
- function search(obj, path = '') {
539
- if (typeof obj !== 'object' || obj === null) return;
540
-
541
- if (Array.isArray(obj)) {
542
- obj.forEach((item, index) => {
543
- search(item, path ? `${path}[${index}]` : `[${index}]`);
544
- });
545
- } else {
546
- for (const [key, value] of Object.entries(obj)) {
547
- const newPath = path ? `${path}.${key}` : key;
548
-
549
- const isMatch = pattern ? pattern.test(key) : key === keyName;
550
- if (isMatch) {
551
- results.push({ path: newPath, value });
552
- }
553
-
554
- if (typeof value === 'object' && value !== null) {
555
- search(value, newPath);
556
- }
557
- }
558
- }
559
- }
560
-
561
- search(jsonObject);
562
- return results;
563
- } catch (error) {
564
- console.error('Error in findKeys:', error);
565
- return [];
566
- }
567
- }
568
-
569
- function deepEqual(obj1, obj2) {
570
- if (obj1 === obj2) return true;
571
-
572
- if (typeof obj1 !== 'object' || obj1 === null ||
573
- typeof obj2 !== 'object' || obj2 === null) {
574
- return false;
575
- }
576
-
577
- const keys1 = Object.keys(obj1);
578
- const keys2 = Object.keys(obj2);
579
-
580
- if (keys1.length !== keys2.length) return false;
581
-
582
- for (const key of keys1) {
583
- if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
584
- return false;
585
- }
586
- }
587
-
588
- return true;
589
- }
590
-
591
- function diff(obj1, obj2, path = '') {
592
- const differences = [];
593
-
594
- if (typeof obj1 !== 'object' || obj1 === null ||
595
- typeof obj2 !== 'object' || obj2 === null) {
596
- if (obj1 !== obj2) {
597
- differences.push({
598
- path,
599
- type: 'value',
600
- old: obj1,
601
- new: obj2
602
- });
603
- }
604
- return differences;
605
- }
606
-
607
- const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
608
-
609
- for (const key of allKeys) {
610
- const newPath = path ? `${path}.${key}` : key;
611
-
612
- if (!(key in obj1)) {
613
- differences.push({
614
- path: newPath,
615
- type: 'added',
616
- value: obj2[key]
617
- });
618
- } else if (!(key in obj2)) {
619
- differences.push({
620
- path: newPath,
621
- type: 'removed',
622
- value: obj1[key]
623
- });
624
- } else if (!deepEqual(obj1[key], obj2[key])) {
625
- if (typeof obj1[key] === 'object' && obj1[key] !== null &&
626
- typeof obj2[key] === 'object' && obj2[key] !== null) {
627
- differences.push(...diff(obj1[key], obj2[key], newPath));
628
- } else {
629
- differences.push({
630
- path: newPath,
631
- type: 'changed',
632
- old: obj1[key],
633
- new: obj2[key]
634
- });
635
- }
636
- }
637
- }
638
-
639
- return differences;
640
- }
641
-
642
- module.exports = {
643
- getString,
644
- getFile,
645
- getData,
646
- getURL,
647
- getContent,
648
- readJSON,
649
- toString,
650
- isValid,
651
- isJSON,
652
- isJSONObject,
653
- getJSON,
654
- beautifyJSON,
655
- beautify,
656
- getAttributes,
657
- getMeta,
658
- getMetaDetail,
659
- getMetaCompact,
660
- getPartial,
661
- getPartialDeep,
662
- getPartialWithDefaults,
663
- excludeAttributes,
664
- getSize,
665
- sortBy,
666
- findKeys,
667
- deepEqual,
668
- diff
669
- };
1
+ const fs = require('fs');
2
+ const https = require('https');
3
+
4
+ function getString(filePath) {
5
+ return fs.readFileSync(filePath, 'utf-8');
6
+ }
7
+
8
+ function getFile(filePath, callback) {
9
+ fs.readFile(filePath, 'utf8', (err, data) => {
10
+ if (err) {
11
+ return;
12
+ } else {
13
+ callback(data);
14
+ }
15
+ });
16
+ }
17
+
18
+ function loadFile(filePath) {
19
+ return new Promise((resolve, reject) => {
20
+ fs.readFile(filePath, 'utf8', (err, data) => {
21
+ if (err) {
22
+ reject(err);
23
+ } else {
24
+ resolve(data);
25
+ }
26
+ });
27
+ });
28
+ }
29
+
30
+ async function getData(filePath) {
31
+ try {
32
+ const data = await loadFile(filePath);
33
+ return data;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ function getURL(url, callback) {
40
+ https.get(url, (response) => {
41
+ let data = '';
42
+ response.on('data', chunk => {
43
+ data += chunk;
44
+ });
45
+ response.on('end', () => {
46
+ callback(data || null);
47
+ });
48
+ }).on('error', (err) => {
49
+ callback(null);
50
+ });
51
+ }
52
+
53
+ function isUrl(input) {
54
+ const urlPattern = /^(https?:\/\/|ftp:\/\/|www\.)/i;
55
+ return urlPattern.test(input);
56
+ }
57
+
58
+ function getContent(target, callback) {
59
+ if (isUrl(target)) {
60
+ getURL(target, callback);
61
+ } else {
62
+ getFile(target, callback);
63
+ }
64
+ }
65
+
66
+ function readJSON(jsonString) {
67
+ return JSON.parse(jsonString);
68
+ }
69
+
70
+ function toString(jsonObject) {
71
+ return JSON.stringify(jsonObject);
72
+ }
73
+
74
+ function isValid(jsonString) {
75
+ try {
76
+ JSON.parse(jsonString);
77
+ return true;
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ function isJSON(jsonObject) {
84
+ try {
85
+ const parsedData = JSON.parse(jsonObject);
86
+ return typeof parsedData === 'object' && parsedData !== null;
87
+ } catch (error) {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ function isJSONObject(jsonObject) {
93
+ try {
94
+ return typeof jsonObject === 'object' && jsonObject !== null && jsonObject !== undefined;
95
+ } catch (error) {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ function getJSON(target, callback) {
101
+ getContent(target, data => {
102
+ if (!data) {
103
+ return callback(null);
104
+ }
105
+ if (!isValid(data)) {
106
+ return callback(null);
107
+ }
108
+ try {
109
+ callback(readJSON(data));
110
+ } catch {
111
+ callback(null);
112
+ }
113
+ });
114
+ }
115
+
116
+ function beautifyJSON(jsonString, indent = 2) {
117
+ try {
118
+ if (typeof jsonString !== 'string') return null;
119
+ const jsonObject = JSON.parse(jsonString);
120
+ return JSON.stringify(jsonObject, null, indent);
121
+ } catch {
122
+ return null;
123
+ }
124
+ }
125
+
126
+ function beautify(jsonObject, indent) {
127
+ try {
128
+ if (!indent) indent = 2;
129
+ return JSON.stringify(jsonObject, null, indent);
130
+ } catch (error) {
131
+ return null;
132
+ }
133
+ }
134
+
135
+ function getAttributes(jsonObject) {
136
+ try {
137
+ if (typeof jsonObject === 'string') {
138
+ jsonObject = JSON.parse(jsonObject);
139
+ }
140
+
141
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
142
+ return [];
143
+ }
144
+
145
+ return Object.keys(jsonObject);
146
+ } catch (error) {
147
+ return [];
148
+ }
149
+ }
150
+
151
+ function getMeta(jsonObject) {
152
+ try {
153
+ if (typeof jsonObject === 'string') {
154
+ jsonObject = JSON.parse(jsonObject);
155
+ }
156
+
157
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
158
+ return {};
159
+ }
160
+
161
+ const meta = {};
162
+
163
+ for (const [key, value] of Object.entries(jsonObject)) {
164
+ let type = typeof value;
165
+
166
+ if (type === 'object') {
167
+ if (value === null) {
168
+ type = 'null';
169
+ } else if (Array.isArray(value)) {
170
+ type = 'array';
171
+ } else if (value instanceof Date) {
172
+ type = 'date';
173
+ } else {
174
+ type = 'object';
175
+ }
176
+ } else if (type === 'number') {
177
+ type = Number.isInteger(value) ? 'integer' : 'float';
178
+ }
179
+
180
+ meta[key] = type;
181
+ }
182
+
183
+ return meta;
184
+ } catch (error) {
185
+ return {};
186
+ }
187
+ }
188
+
189
+ function getMetaDetail(jsonObject) {
190
+ try {
191
+ if (typeof jsonObject === 'string') {
192
+ jsonObject = JSON.parse(jsonObject);
193
+ }
194
+
195
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
196
+ return {};
197
+ }
198
+
199
+ function getNestedMeta(obj, path = '') {
200
+ const meta = {};
201
+
202
+ for (const [key, value] of Object.entries(obj)) {
203
+ const currentPath = path ? `${path}.${key}` : key;
204
+ const attributeMeta = {};
205
+
206
+ let type = typeof value;
207
+
208
+ if (value === null) {
209
+ type = 'null';
210
+ attributeMeta.type = type;
211
+ attributeMeta.isRequired = false;
212
+ attributeMeta.path = currentPath;
213
+ } else if (Array.isArray(value)) {
214
+ type = 'array';
215
+ attributeMeta.type = type;
216
+ attributeMeta.length = value.length;
217
+ attributeMeta.isRequired = true;
218
+ attributeMeta.path = currentPath;
219
+
220
+ if (value.length > 0) {
221
+ const firstElement = value[0];
222
+ const elementType = typeof firstElement;
223
+
224
+ if (elementType === 'object' && firstElement !== null) {
225
+ if (Array.isArray(firstElement)) {
226
+ attributeMeta.elementType = 'array';
227
+ } else {
228
+ attributeMeta.elementType = 'object';
229
+ attributeMeta.children = getNestedMeta(firstElement, `${currentPath}[0]`);
230
+ }
231
+ } else {
232
+ attributeMeta.elementType = elementType;
233
+ }
234
+ } else {
235
+ attributeMeta.elementType = 'unknown';
236
+ }
237
+ } else if (value instanceof Date) {
238
+ type = 'date';
239
+ attributeMeta.type = type;
240
+ attributeMeta.isRequired = true;
241
+ attributeMeta.path = currentPath;
242
+ } else if (type === 'object') {
243
+ type = 'object';
244
+ attributeMeta.type = type;
245
+ attributeMeta.isRequired = true;
246
+ attributeMeta.path = currentPath;
247
+ attributeMeta.keysCount = Object.keys(value).length;
248
+
249
+ attributeMeta.children = getNestedMeta(value, currentPath);
250
+ } else {
251
+ attributeMeta.type = type;
252
+ attributeMeta.isRequired = true;
253
+ attributeMeta.path = currentPath;
254
+
255
+ if (type === 'number') {
256
+ attributeMeta.numberType = Number.isInteger(value) ? 'integer' : 'float';
257
+ }
258
+ }
259
+
260
+ meta[key] = attributeMeta;
261
+ }
262
+
263
+ return meta;
264
+ }
265
+
266
+ return getNestedMeta(jsonObject);
267
+ } catch (error) {
268
+ console.error('Error in getMetaDetail:', error);
269
+ return {};
270
+ }
271
+ }
272
+
273
+ function getMetaCompact(jsonObject) {
274
+ try {
275
+ if (typeof jsonObject === 'string') {
276
+ jsonObject = JSON.parse(jsonObject);
277
+ }
278
+
279
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
280
+ return {};
281
+ }
282
+
283
+ function getCompactMeta(obj) {
284
+ const meta = {};
285
+
286
+ for (const [key, value] of Object.entries(obj)) {
287
+ let type = typeof value;
288
+
289
+ if (value === null) {
290
+ meta[key] = 'null';
291
+ } else if (Array.isArray(value)) {
292
+ if (value.length > 0) {
293
+ const firstElement = value[0];
294
+ const elementType = typeof firstElement;
295
+ if (elementType === 'object' && firstElement !== null) {
296
+ meta[key] = `array[${Array.isArray(firstElement) ? 'array' : 'object'}]`;
297
+ } else {
298
+ meta[key] = `array[${elementType}]`;
299
+ }
300
+ } else {
301
+ meta[key] = 'array[]';
302
+ }
303
+ } else if (value instanceof Date) {
304
+ meta[key] = 'date';
305
+ } else if (type === 'object') {
306
+ meta[key] = getCompactMeta(value);
307
+ } else if (type === 'number') {
308
+ meta[key] = Number.isInteger(value) ? 'integer' : 'float';
309
+ } else {
310
+ meta[key] = type;
311
+ }
312
+ }
313
+
314
+ return meta;
315
+ }
316
+
317
+ return getCompactMeta(jsonObject);
318
+ } catch (error) {
319
+ console.error('Error in getMetaCompact:', error);
320
+ return {};
321
+ }
322
+ }
323
+
324
+ function getPartial(jsonObject, attributes) {
325
+ try {
326
+ if (typeof jsonObject === 'string') {
327
+ jsonObject = JSON.parse(jsonObject);
328
+ }
329
+
330
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
331
+ return {};
332
+ }
333
+
334
+ const result = {};
335
+
336
+ if (Array.isArray(attributes)) {
337
+ for (const attr of attributes) {
338
+ if (attr in jsonObject) {
339
+ result[attr] = jsonObject[attr];
340
+ }
341
+ }
342
+ }
343
+ else if (typeof attributes === 'string') {
344
+ if (attributes in jsonObject) {
345
+ result[attributes] = jsonObject[attributes];
346
+ }
347
+ }
348
+ else if (typeof attributes === 'object' && attributes !== null) {
349
+ for (const [newKey, originalKey] of Object.entries(attributes)) {
350
+ if (originalKey in jsonObject) {
351
+ result[newKey] = jsonObject[originalKey];
352
+ }
353
+ }
354
+ }
355
+
356
+ return result;
357
+ } catch (error) {
358
+ console.error('Error in getPartial:', error);
359
+ return {};
360
+ }
361
+ }
362
+
363
+ function getPartialDeep(jsonObject, attributePaths) {
364
+ try {
365
+ if (typeof jsonObject === 'string') {
366
+ jsonObject = JSON.parse(jsonObject);
367
+ }
368
+
369
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
370
+ return {};
371
+ }
372
+
373
+ const result = {};
374
+
375
+ function getValueFromPath(obj, path) {
376
+ const parts = path.split('.');
377
+ let current = obj;
378
+
379
+ for (const part of parts) {
380
+ if (current && typeof current === 'object' && part in current) {
381
+ current = current[part];
382
+ } else {
383
+ return undefined;
384
+ }
385
+ }
386
+
387
+ return current;
388
+ }
389
+
390
+ if (Array.isArray(attributePaths)) {
391
+ for (const path of attributePaths) {
392
+ const value = getValueFromPath(jsonObject, path);
393
+ if (value !== undefined) {
394
+ const key = path.split('.').pop();
395
+ result[key] = value;
396
+ }
397
+ }
398
+ }
399
+ else if (typeof attributePaths === 'object' && attributePaths !== null) {
400
+ for (const [newKey, path] of Object.entries(attributePaths)) {
401
+ const value = getValueFromPath(jsonObject, path);
402
+ if (value !== undefined) {
403
+ result[newKey] = value;
404
+ }
405
+ }
406
+ }
407
+
408
+ return result;
409
+ } catch (error) {
410
+ console.error('Error in getPartialDeep:', error);
411
+ return {};
412
+ }
413
+ }
414
+
415
+ function getPartialWithDefaults(jsonObject, attributesConfig) {
416
+ try {
417
+ if (typeof jsonObject === 'string') {
418
+ jsonObject = JSON.parse(jsonObject);
419
+ }
420
+
421
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
422
+ return {};
423
+ }
424
+
425
+ const result = {};
426
+
427
+ function getValueFromPath(obj, path, defaultValue) {
428
+ const parts = path.split('.');
429
+ let current = obj;
430
+
431
+ for (const part of parts) {
432
+ if (current && typeof current === 'object' && part in current) {
433
+ current = current[part];
434
+ } else {
435
+ return defaultValue;
436
+ }
437
+ }
438
+
439
+ return current;
440
+ }
441
+
442
+ for (const [outputKey, config] of Object.entries(attributesConfig)) {
443
+ if (typeof config === 'string') {
444
+ result[outputKey] = getValueFromPath(jsonObject, config, undefined);
445
+ } else if (typeof config === 'object' && config !== null) {
446
+ const path = config.path || outputKey;
447
+ const defaultValue = config.default;
448
+ let value = getValueFromPath(jsonObject, path, defaultValue);
449
+
450
+ if (config.transform && typeof config.transform === 'function') {
451
+ value = config.transform(value);
452
+ }
453
+
454
+ result[outputKey] = value;
455
+ }
456
+ }
457
+
458
+ return result;
459
+ } catch (error) {
460
+ console.error('Error in getPartialWithDefaults:', error);
461
+ return {};
462
+ }
463
+ }
464
+
465
+ function excludeAttributes(jsonObject, attributesToExclude) {
466
+ try {
467
+ if (typeof jsonObject === 'string') {
468
+ jsonObject = JSON.parse(jsonObject);
469
+ }
470
+
471
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
472
+ return {};
473
+ }
474
+
475
+ const result = { ...jsonObject };
476
+
477
+ if (Array.isArray(attributesToExclude)) {
478
+ for (const attr of attributesToExclude) {
479
+ delete result[attr];
480
+ }
481
+ }
482
+ else if (typeof attributesToExclude === 'string') {
483
+ delete result[attributesToExclude];
484
+ }
485
+
486
+ return result;
487
+ } catch (error) {
488
+ console.error('Error in excludeAttributes:', error);
489
+ return {};
490
+ }
491
+ }
492
+
493
+ function getSize(jsonObject) {
494
+ try {
495
+ const jsonString = typeof jsonObject === 'string'
496
+ ? jsonObject
497
+ : JSON.stringify(jsonObject);
498
+ return new Blob([jsonString]).size;
499
+ } catch (error) {
500
+ console.error('Error in getSize:', error);
501
+ return 0;
502
+ }
503
+ }
504
+
505
+ function sortBy(array, key, ascending = true) {
506
+ try {
507
+ if (!Array.isArray(array)) return array;
508
+
509
+ return [...array].sort((a, b) => {
510
+ const aValue = typeof key === 'function' ? key(a) : a[key];
511
+ const bValue = typeof key === 'function' ? key(b) : b[key];
512
+
513
+ if (aValue < bValue) return ascending ? -1 : 1;
514
+ if (aValue > bValue) return ascending ? 1 : -1;
515
+ return 0;
516
+ });
517
+ } catch (error) {
518
+ console.error('Error in sortBy:', error);
519
+ return array;
520
+ }
521
+ }
522
+
523
+ function findKeys(jsonObject, keyName) {
524
+ try {
525
+ if (typeof jsonObject === 'string') {
526
+ jsonObject = JSON.parse(jsonObject);
527
+ }
528
+
529
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
530
+ return [];
531
+ }
532
+
533
+ const results = [];
534
+ const pattern = keyName.includes('*')
535
+ ? new RegExp('^' + keyName.replace(/\*/g, '.*') + '$')
536
+ : null;
537
+
538
+ function search(obj, path = '') {
539
+ if (typeof obj !== 'object' || obj === null) return;
540
+
541
+ if (Array.isArray(obj)) {
542
+ obj.forEach((item, index) => {
543
+ search(item, path ? `${path}[${index}]` : `[${index}]`);
544
+ });
545
+ } else {
546
+ for (const [key, value] of Object.entries(obj)) {
547
+ const newPath = path ? `${path}.${key}` : key;
548
+
549
+ const isMatch = pattern ? pattern.test(key) : key === keyName;
550
+ if (isMatch) {
551
+ results.push({ path: newPath, value });
552
+ }
553
+
554
+ if (typeof value === 'object' && value !== null) {
555
+ search(value, newPath);
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ search(jsonObject);
562
+ return results;
563
+ } catch (error) {
564
+ console.error('Error in findKeys:', error);
565
+ return [];
566
+ }
567
+ }
568
+
569
+ function deepEqual(obj1, obj2) {
570
+ if (obj1 === obj2) return true;
571
+
572
+ if (typeof obj1 !== 'object' || obj1 === null ||
573
+ typeof obj2 !== 'object' || obj2 === null) {
574
+ return false;
575
+ }
576
+
577
+ const keys1 = Object.keys(obj1);
578
+ const keys2 = Object.keys(obj2);
579
+
580
+ if (keys1.length !== keys2.length) return false;
581
+
582
+ for (const key of keys1) {
583
+ if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
584
+ return false;
585
+ }
586
+ }
587
+
588
+ return true;
589
+ }
590
+
591
+ function diff(obj1, obj2, path = '') {
592
+ const differences = [];
593
+
594
+ if (typeof obj1 !== 'object' || obj1 === null ||
595
+ typeof obj2 !== 'object' || obj2 === null) {
596
+ if (obj1 !== obj2) {
597
+ differences.push({
598
+ path,
599
+ type: 'value',
600
+ old: obj1,
601
+ new: obj2
602
+ });
603
+ }
604
+ return differences;
605
+ }
606
+
607
+ const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
608
+
609
+ for (const key of allKeys) {
610
+ const newPath = path ? `${path}.${key}` : key;
611
+
612
+ if (!(key in obj1)) {
613
+ differences.push({
614
+ path: newPath,
615
+ type: 'added',
616
+ value: obj2[key]
617
+ });
618
+ } else if (!(key in obj2)) {
619
+ differences.push({
620
+ path: newPath,
621
+ type: 'removed',
622
+ value: obj1[key]
623
+ });
624
+ } else if (!deepEqual(obj1[key], obj2[key])) {
625
+ if (typeof obj1[key] === 'object' && obj1[key] !== null &&
626
+ typeof obj2[key] === 'object' && obj2[key] !== null) {
627
+ differences.push(...diff(obj1[key], obj2[key], newPath));
628
+ } else {
629
+ differences.push({
630
+ path: newPath,
631
+ type: 'changed',
632
+ old: obj1[key],
633
+ new: obj2[key]
634
+ });
635
+ }
636
+ }
637
+ }
638
+
639
+ return differences;
640
+ }
641
+
642
+ function searchValues(jsonObject, predicate) {
643
+ try {
644
+ if (typeof jsonObject === 'string') {
645
+ jsonObject = JSON.parse(jsonObject);
646
+ }
647
+
648
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
649
+ return [];
650
+ }
651
+
652
+ const results = [];
653
+
654
+ function search(obj, path = '') {
655
+ if (typeof obj !== 'object' || obj === null) {
656
+ if (predicate(obj)) {
657
+ results.push({ path, value: obj });
658
+ }
659
+ return;
660
+ }
661
+
662
+ if (Array.isArray(obj)) {
663
+ obj.forEach((item, index) => {
664
+ search(item, path ? `${path}[${index}]` : `[${index}]`);
665
+ });
666
+ } else {
667
+ for (const [key, value] of Object.entries(obj)) {
668
+ const newPath = path ? `${path}.${key}` : key;
669
+
670
+ if (predicate(value)) {
671
+ results.push({ path: newPath, value });
672
+ }
673
+
674
+ if (typeof value === 'object' && value !== null) {
675
+ search(value, newPath);
676
+ }
677
+ }
678
+ }
679
+ }
680
+
681
+ search(jsonObject);
682
+ return results;
683
+ } catch (error) {
684
+ console.error('Error in searchValues:', error);
685
+ return [];
686
+ }
687
+ }
688
+
689
+ function findValue(jsonObject, targetValue, deep = true) {
690
+ return searchValues(jsonObject, (value) => {
691
+ if (typeof targetValue === 'function') {
692
+ return targetValue(value);
693
+ }
694
+ return value === targetValue;
695
+ });
696
+ }
697
+
698
+ function deepMerge(target, source) {
699
+ if (typeof target !== 'object' || target === null) return source;
700
+ if (typeof source !== 'object' || source === null) return target;
701
+
702
+ const output = { ...target };
703
+
704
+ for (const [key, value] of Object.entries(source)) {
705
+ if (key in target &&
706
+ typeof target[key] === 'object' && target[key] !== null &&
707
+ typeof value === 'object' && value !== null &&
708
+ !Array.isArray(target[key]) && !Array.isArray(value)) {
709
+ output[key] = deepMerge(target[key], value);
710
+ } else {
711
+ output[key] = value;
712
+ }
713
+ }
714
+
715
+ return output;
716
+ }
717
+
718
+ function filterProperties(jsonObject, predicate) {
719
+ try {
720
+ if (typeof jsonObject === 'string') {
721
+ jsonObject = JSON.parse(jsonObject);
722
+ }
723
+
724
+ if (typeof jsonObject !== 'object' || jsonObject === null) {
725
+ return {};
726
+ }
727
+
728
+ const result = {};
729
+
730
+ for (const [key, value] of Object.entries(jsonObject)) {
731
+ if (predicate(key, value)) {
732
+ result[key] = value;
733
+ }
734
+ }
735
+
736
+ return result;
737
+ } catch (error) {
738
+ console.error('Error in filterProperties:', error);
739
+ return {};
740
+ }
741
+ }
742
+
743
+ function filterByType(jsonObject, type) {
744
+ return filterProperties(jsonObject, (key, value) => {
745
+ if (type === 'array') return Array.isArray(value);
746
+ if (type === 'null') return value === null;
747
+ if (type === 'date') return value instanceof Date;
748
+ if (type === 'integer') return typeof value === 'number' && Number.isInteger(value);
749
+ if (type === 'float') return typeof value === 'number' && !Number.isInteger(value);
750
+ return typeof value === type;
751
+ });
752
+ }
753
+
754
+ function removeEmptyProperties(jsonObject, includeEmptyStrings = false) {
755
+ return filterProperties(jsonObject, (key, value) => {
756
+ if (value === null || value === undefined) return false;
757
+ if (includeEmptyStrings && value === '') return false;
758
+ if (Array.isArray(value) && value.length === 0) return false;
759
+ if (typeof value === 'object' && Object.keys(value).length === 0) return false;
760
+ return true;
761
+ });
762
+ }
763
+
764
+ function filterByKeyPattern(jsonObject, pattern) {
765
+ const regex = new RegExp(pattern);
766
+ return filterProperties(jsonObject, (key) => regex.test(key));
767
+ }
768
+
769
+ module.exports = {
770
+ getString,
771
+ getFile,
772
+ getData,
773
+ getURL,
774
+ getContent,
775
+ readJSON,
776
+ toString,
777
+ isValid,
778
+ isJSON,
779
+ isJSONObject,
780
+ getJSON,
781
+ beautifyJSON,
782
+ beautify,
783
+ getAttributes,
784
+ getMeta,
785
+ getMetaDetail,
786
+ getMetaCompact,
787
+ getPartial,
788
+ getPartialDeep,
789
+ getPartialWithDefaults,
790
+ excludeAttributes,
791
+ getSize,
792
+ sortBy,
793
+ findKeys,
794
+ deepEqual,
795
+ diff,
796
+ searchValues,
797
+ findValue,
798
+ deepMerge,
799
+ filterProperties,
800
+ filterByType,
801
+ removeEmptyProperties,
802
+ filterByKeyPattern
803
+ };