@gzl10/ts-helpers 4.2.1
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/CHANGELOG.md +320 -0
- package/README.md +233 -0
- package/USAGE-GUIDE.md +800 -0
- package/dist/browser/async.js +15 -0
- package/dist/browser/async.js.map +1 -0
- package/dist/browser/chunk-4O7ZPIJN.js +383 -0
- package/dist/browser/chunk-4O7ZPIJN.js.map +1 -0
- package/dist/browser/chunk-75XNTC34.js +60 -0
- package/dist/browser/chunk-75XNTC34.js.map +1 -0
- package/dist/browser/chunk-C3D7YZVE.js +299 -0
- package/dist/browser/chunk-C3D7YZVE.js.map +1 -0
- package/dist/browser/chunk-CZL6C2EI.js +452 -0
- package/dist/browser/chunk-CZL6C2EI.js.map +1 -0
- package/dist/browser/chunk-D4FZFIVA.js +240 -0
- package/dist/browser/chunk-D4FZFIVA.js.map +1 -0
- package/dist/browser/chunk-IL7NG7IC.js +72 -0
- package/dist/browser/chunk-IL7NG7IC.js.map +1 -0
- package/dist/browser/chunk-NSBPE2FW.js +17 -0
- package/dist/browser/chunk-NSBPE2FW.js.map +1 -0
- package/dist/browser/chunk-SLQVNPTH.js +27 -0
- package/dist/browser/chunk-SLQVNPTH.js.map +1 -0
- package/dist/browser/chunk-WG7ILCUB.js +195 -0
- package/dist/browser/chunk-WG7ILCUB.js.map +1 -0
- package/dist/browser/chunk-WJA4JDMZ.js +278 -0
- package/dist/browser/chunk-WJA4JDMZ.js.map +1 -0
- package/dist/browser/chunk-ZFVYLUTT.js +65 -0
- package/dist/browser/chunk-ZFVYLUTT.js.map +1 -0
- package/dist/browser/chunk-ZYTSVMTI.js +263 -0
- package/dist/browser/chunk-ZYTSVMTI.js.map +1 -0
- package/dist/browser/dates.js +78 -0
- package/dist/browser/dates.js.map +1 -0
- package/dist/browser/environment-detection.js +21 -0
- package/dist/browser/environment-detection.js.map +1 -0
- package/dist/browser/environment.js +34 -0
- package/dist/browser/environment.js.map +1 -0
- package/dist/browser/errors.js +18 -0
- package/dist/browser/errors.js.map +1 -0
- package/dist/browser/index.js +412 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/math.js +51 -0
- package/dist/browser/math.js.map +1 -0
- package/dist/browser/number.js +10 -0
- package/dist/browser/number.js.map +1 -0
- package/dist/browser/objects.js +31 -0
- package/dist/browser/objects.js.map +1 -0
- package/dist/browser/strings.js +80 -0
- package/dist/browser/strings.js.map +1 -0
- package/dist/browser/validation-core.js +54 -0
- package/dist/browser/validation-core.js.map +1 -0
- package/dist/browser/validation-crypto.js +28 -0
- package/dist/browser/validation-crypto.js.map +1 -0
- package/dist/browser/validators.js +98 -0
- package/dist/browser/validators.js.map +1 -0
- package/dist/cjs/async.js +86 -0
- package/dist/cjs/async.js.map +1 -0
- package/dist/cjs/dates.js +285 -0
- package/dist/cjs/dates.js.map +1 -0
- package/dist/cjs/environment-detection.js +84 -0
- package/dist/cjs/environment-detection.js.map +1 -0
- package/dist/cjs/environment.js +261 -0
- package/dist/cjs/environment.js.map +1 -0
- package/dist/cjs/errors.js +80 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.js +2035 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/math.js +388 -0
- package/dist/cjs/math.js.map +1 -0
- package/dist/cjs/number.js +37 -0
- package/dist/cjs/number.js.map +1 -0
- package/dist/cjs/objects.js +249 -0
- package/dist/cjs/objects.js.map +1 -0
- package/dist/cjs/strings.js +253 -0
- package/dist/cjs/strings.js.map +1 -0
- package/dist/cjs/validation.js +450 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/esm/async.js +15 -0
- package/dist/esm/async.js.map +1 -0
- package/dist/esm/chunk-4O7ZPIJN.js +383 -0
- package/dist/esm/chunk-4O7ZPIJN.js.map +1 -0
- package/dist/esm/chunk-75XNTC34.js +60 -0
- package/dist/esm/chunk-75XNTC34.js.map +1 -0
- package/dist/esm/chunk-BDOBKBKA.js +72 -0
- package/dist/esm/chunk-BDOBKBKA.js.map +1 -0
- package/dist/esm/chunk-C3D7YZVE.js +299 -0
- package/dist/esm/chunk-C3D7YZVE.js.map +1 -0
- package/dist/esm/chunk-CZL6C2EI.js +452 -0
- package/dist/esm/chunk-CZL6C2EI.js.map +1 -0
- package/dist/esm/chunk-EBLSTOEC.js +263 -0
- package/dist/esm/chunk-EBLSTOEC.js.map +1 -0
- package/dist/esm/chunk-NSBPE2FW.js +17 -0
- package/dist/esm/chunk-NSBPE2FW.js.map +1 -0
- package/dist/esm/chunk-SLQVNPTH.js +27 -0
- package/dist/esm/chunk-SLQVNPTH.js.map +1 -0
- package/dist/esm/chunk-WG7ILCUB.js +195 -0
- package/dist/esm/chunk-WG7ILCUB.js.map +1 -0
- package/dist/esm/chunk-WJA4JDMZ.js +278 -0
- package/dist/esm/chunk-WJA4JDMZ.js.map +1 -0
- package/dist/esm/chunk-ZFVYLUTT.js +65 -0
- package/dist/esm/chunk-ZFVYLUTT.js.map +1 -0
- package/dist/esm/dates.js +78 -0
- package/dist/esm/dates.js.map +1 -0
- package/dist/esm/environment-detection.js +21 -0
- package/dist/esm/environment-detection.js.map +1 -0
- package/dist/esm/environment.js +34 -0
- package/dist/esm/environment.js.map +1 -0
- package/dist/esm/errors.js +18 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.js +380 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/math.js +51 -0
- package/dist/esm/math.js.map +1 -0
- package/dist/esm/number.js +10 -0
- package/dist/esm/number.js.map +1 -0
- package/dist/esm/objects.js +31 -0
- package/dist/esm/objects.js.map +1 -0
- package/dist/esm/strings.js +80 -0
- package/dist/esm/strings.js.map +1 -0
- package/dist/esm/validation.js +54 -0
- package/dist/esm/validation.js.map +1 -0
- package/dist/node/async.js +93 -0
- package/dist/node/async.js.map +1 -0
- package/dist/node/csv.js +102 -0
- package/dist/node/csv.js.map +1 -0
- package/dist/node/data.js +880 -0
- package/dist/node/data.js.map +1 -0
- package/dist/node/dates.js +324 -0
- package/dist/node/dates.js.map +1 -0
- package/dist/node/environment.js +278 -0
- package/dist/node/environment.js.map +1 -0
- package/dist/node/errors.js +89 -0
- package/dist/node/errors.js.map +1 -0
- package/dist/node/index.js +3151 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/json.js +107 -0
- package/dist/node/json.js.map +1 -0
- package/dist/node/math.js +413 -0
- package/dist/node/math.js.map +1 -0
- package/dist/node/number.js +42 -0
- package/dist/node/number.js.map +1 -0
- package/dist/node/objects.js +264 -0
- package/dist/node/objects.js.map +1 -0
- package/dist/node/strings.js +293 -0
- package/dist/node/strings.js.map +1 -0
- package/dist/node/tree.js +89 -0
- package/dist/node/tree.js.map +1 -0
- package/dist/node/validation-core.js +477 -0
- package/dist/node/validation-core.js.map +1 -0
- package/dist/node/validation-crypto.js +179 -0
- package/dist/node/validation-crypto.js.map +1 -0
- package/dist/node/validation.js +677 -0
- package/dist/node/validation.js.map +1 -0
- package/dist/node/validators.js +123 -0
- package/dist/node/validators.js.map +1 -0
- package/dist/node-esm/async.js +15 -0
- package/dist/node-esm/async.js.map +1 -0
- package/dist/node-esm/chunk-3YOF7NPT.js +299 -0
- package/dist/node-esm/chunk-3YOF7NPT.js.map +1 -0
- package/dist/node-esm/chunk-64TBXJQS.js +263 -0
- package/dist/node-esm/chunk-64TBXJQS.js.map +1 -0
- package/dist/node-esm/chunk-75XNTC34.js +60 -0
- package/dist/node-esm/chunk-75XNTC34.js.map +1 -0
- package/dist/node-esm/chunk-C4PKXIPB.js +278 -0
- package/dist/node-esm/chunk-C4PKXIPB.js.map +1 -0
- package/dist/node-esm/chunk-CMDFZME3.js +452 -0
- package/dist/node-esm/chunk-CMDFZME3.js.map +1 -0
- package/dist/node-esm/chunk-DZZPUYMP.js +74 -0
- package/dist/node-esm/chunk-DZZPUYMP.js.map +1 -0
- package/dist/node-esm/chunk-HTSEHRHI.js +195 -0
- package/dist/node-esm/chunk-HTSEHRHI.js.map +1 -0
- package/dist/node-esm/chunk-JCAUVOPH.js +27 -0
- package/dist/node-esm/chunk-JCAUVOPH.js.map +1 -0
- package/dist/node-esm/chunk-KBHE3K2F.js +505 -0
- package/dist/node-esm/chunk-KBHE3K2F.js.map +1 -0
- package/dist/node-esm/chunk-LYTET5NX.js +65 -0
- package/dist/node-esm/chunk-LYTET5NX.js.map +1 -0
- package/dist/node-esm/chunk-PZ5AY32C.js +10 -0
- package/dist/node-esm/chunk-PZ5AY32C.js.map +1 -0
- package/dist/node-esm/chunk-UKGXL2QO.js +383 -0
- package/dist/node-esm/chunk-UKGXL2QO.js.map +1 -0
- package/dist/node-esm/chunk-XAEYT23H.js +164 -0
- package/dist/node-esm/chunk-XAEYT23H.js.map +1 -0
- package/dist/node-esm/csv.js +63 -0
- package/dist/node-esm/csv.js.map +1 -0
- package/dist/node-esm/data.js +32 -0
- package/dist/node-esm/data.js.map +1 -0
- package/dist/node-esm/dates.js +78 -0
- package/dist/node-esm/dates.js.map +1 -0
- package/dist/node-esm/environment.js +34 -0
- package/dist/node-esm/environment.js.map +1 -0
- package/dist/node-esm/errors.js +18 -0
- package/dist/node-esm/errors.js.map +1 -0
- package/dist/node-esm/index.js +426 -0
- package/dist/node-esm/index.js.map +1 -0
- package/dist/node-esm/json.js +68 -0
- package/dist/node-esm/json.js.map +1 -0
- package/dist/node-esm/math.js +51 -0
- package/dist/node-esm/math.js.map +1 -0
- package/dist/node-esm/number.js +10 -0
- package/dist/node-esm/number.js.map +1 -0
- package/dist/node-esm/objects.js +31 -0
- package/dist/node-esm/objects.js.map +1 -0
- package/dist/node-esm/strings.js +80 -0
- package/dist/node-esm/strings.js.map +1 -0
- package/dist/node-esm/tree.js +8 -0
- package/dist/node-esm/tree.js.map +1 -0
- package/dist/node-esm/validation-core.js +54 -0
- package/dist/node-esm/validation-core.js.map +1 -0
- package/dist/node-esm/validation-crypto.js +26 -0
- package/dist/node-esm/validation-crypto.js.map +1 -0
- package/dist/node-esm/validation.js +606 -0
- package/dist/node-esm/validation.js.map +1 -0
- package/dist/node-esm/validators.js +98 -0
- package/dist/node-esm/validators.js.map +1 -0
- package/dist/types/async-C8gvbSG-.d.ts +453 -0
- package/dist/types/async.d.ts +1 -0
- package/dist/types/csv.d.ts +226 -0
- package/dist/types/data.d.ts +1561 -0
- package/dist/types/dates-hTiE0Z11.d.ts +298 -0
- package/dist/types/dates.d.ts +1 -0
- package/dist/types/environment-B8eLS7KT.d.ts +420 -0
- package/dist/types/environment-detection.d.ts +102 -0
- package/dist/types/environment.d.ts +1 -0
- package/dist/types/errors.d.ts +147 -0
- package/dist/types/index.d.ts +211 -0
- package/dist/types/json.d.ts +284 -0
- package/dist/types/math-BQ9Lwdp7.d.ts +2060 -0
- package/dist/types/math.d.ts +1 -0
- package/dist/types/number-CYnQfLWj.d.ts +44 -0
- package/dist/types/number.d.ts +1 -0
- package/dist/types/objects-BohS8GCS.d.ts +1185 -0
- package/dist/types/objects.d.ts +1 -0
- package/dist/types/strings-CiqRPYLL.d.ts +1349 -0
- package/dist/types/strings.d.ts +1 -0
- package/dist/types/tree.d.ts +284 -0
- package/dist/types/validation-core-DfHF8rCG.d.ts +238 -0
- package/dist/types/validation-crypto-browser.d.ts +56 -0
- package/dist/types/validation-crypto-node.d.ts +31 -0
- package/dist/types/validation.d.ts +1 -0
- package/dist/types/validators.d.ts +216 -0
- package/package.json +253 -0
|
@@ -0,0 +1,1185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object manipulation and comparison utilities
|
|
3
|
+
* Consolidated from primitives/object and array modules
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Compares two objects utilizing lodash deep comparison
|
|
7
|
+
* @deprecated Use `deepEqual` instead for consistency
|
|
8
|
+
* @param data1 First object to compare
|
|
9
|
+
* @param data2 Second object to compare
|
|
10
|
+
* @returns True if objects are deeply equal, false otherwise
|
|
11
|
+
*/
|
|
12
|
+
declare const comparator: (data1: any, data2: any) => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Performs fast deep comparison between two values
|
|
15
|
+
*
|
|
16
|
+
* Compares values recursively including nested objects, arrays, dates, RegExp, and primitives.
|
|
17
|
+
* Uses fast-deep-equal library for optimal performance (~5-10x faster than JSON.stringify).
|
|
18
|
+
*
|
|
19
|
+
* Comparison rules:
|
|
20
|
+
* - Primitives: strict equality (===)
|
|
21
|
+
* - Objects: recursive key-value comparison
|
|
22
|
+
* - Arrays: length + element-by-element comparison
|
|
23
|
+
* - Dates: compares timestamps
|
|
24
|
+
* - RegExp: compares source and flags
|
|
25
|
+
* - null/undefined: strict equality
|
|
26
|
+
*
|
|
27
|
+
* Use cases: Testing, change detection, cache invalidation, data validation
|
|
28
|
+
*
|
|
29
|
+
* @param data1 - First value to compare (any type)
|
|
30
|
+
* @param data2 - Second value to compare (any type)
|
|
31
|
+
* @returns True if values are deeply equal, false otherwise
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* // Primitive values
|
|
36
|
+
* deepEqual(42, 42) // true
|
|
37
|
+
* deepEqual('hello', 'hello') // true
|
|
38
|
+
* deepEqual(null, null) // true
|
|
39
|
+
* deepEqual(42, '42') // false (different types)
|
|
40
|
+
*
|
|
41
|
+
* // Objects
|
|
42
|
+
* deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 }) // true
|
|
43
|
+
* deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 }) // true (order doesn't matter)
|
|
44
|
+
* deepEqual({ a: 1 }, { a: 1, b: undefined }) // false
|
|
45
|
+
*
|
|
46
|
+
* // Arrays
|
|
47
|
+
* deepEqual([1, 2, 3], [1, 2, 3]) // true
|
|
48
|
+
* deepEqual([1, 2, 3], [3, 2, 1]) // false (order matters)
|
|
49
|
+
*
|
|
50
|
+
* // Nested structures
|
|
51
|
+
* deepEqual(
|
|
52
|
+
* { user: { name: 'Alice', tags: ['admin'] } },
|
|
53
|
+
* { user: { name: 'Alice', tags: ['admin'] } }
|
|
54
|
+
* ) // true
|
|
55
|
+
*
|
|
56
|
+
* // Dates
|
|
57
|
+
* deepEqual(new Date('2024-01-01'), new Date('2024-01-01')) // true
|
|
58
|
+
* deepEqual(new Date('2024-01-01'), new Date('2024-01-02')) // false
|
|
59
|
+
*
|
|
60
|
+
* // RegExp
|
|
61
|
+
* deepEqual(/test/gi, /test/gi) // true
|
|
62
|
+
* deepEqual(/test/g, /test/i) // false
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* // Real-world: Detect if form data changed
|
|
68
|
+
* const originalData = {
|
|
69
|
+
* name: 'John Doe',
|
|
70
|
+
* email: 'john@example.com',
|
|
71
|
+
* preferences: { theme: 'dark', notifications: true }
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* const currentData = {
|
|
75
|
+
* name: 'John Doe',
|
|
76
|
+
* email: 'john.doe@example.com', // Changed!
|
|
77
|
+
* preferences: { theme: 'dark', notifications: true }
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* const hasChanges = !deepEqual(originalData, currentData)
|
|
81
|
+
* if (hasChanges) {
|
|
82
|
+
* console.log('⚠️ You have unsaved changes')
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // Real-world: Cache invalidation
|
|
89
|
+
* const cache = new Map<string, { params: any; result: any }>()
|
|
90
|
+
*
|
|
91
|
+
* function cachedApiCall(params: any) {
|
|
92
|
+
* const cacheKey = 'api-call'
|
|
93
|
+
* const cached = cache.get(cacheKey)
|
|
94
|
+
*
|
|
95
|
+
* // Check if cached params match current params
|
|
96
|
+
* if (cached && deepEqual(cached.params, params)) {
|
|
97
|
+
* console.log('✅ Cache hit')
|
|
98
|
+
* return cached.result
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* console.log('❌ Cache miss - fetching')
|
|
102
|
+
* const result = fetchData(params)
|
|
103
|
+
* cache.set(cacheKey, { params, result })
|
|
104
|
+
* return result
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* // Real-world: React shouldComponentUpdate optimization
|
|
111
|
+
* class UserProfile extends React.Component {
|
|
112
|
+
* shouldComponentUpdate(nextProps: any) {
|
|
113
|
+
* // Only re-render if props actually changed
|
|
114
|
+
* return !deepEqual(this.props, nextProps)
|
|
115
|
+
* }
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* // Real-world: Testing
|
|
122
|
+
* import { deepEqual } from '@g10/ts-helpers'
|
|
123
|
+
*
|
|
124
|
+
* test('API returns expected user structure', async () => {
|
|
125
|
+
* const response = await api.getUser(123)
|
|
126
|
+
*
|
|
127
|
+
* const expected = {
|
|
128
|
+
* id: 123,
|
|
129
|
+
* name: 'Alice',
|
|
130
|
+
* roles: ['user', 'admin'],
|
|
131
|
+
* metadata: { lastLogin: expect.any(Date) }
|
|
132
|
+
* }
|
|
133
|
+
*
|
|
134
|
+
* // Deep comparison ignoring date instance
|
|
135
|
+
* expect(deepEqual(
|
|
136
|
+
* { ...response, metadata: { ...response.metadata, lastLogin: null } },
|
|
137
|
+
* { ...expected, metadata: { ...expected.metadata, lastLogin: null } }
|
|
138
|
+
* )).toBe(true)
|
|
139
|
+
* })
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @see {@link calculateDifferences} for finding specific differences between objects
|
|
143
|
+
* @see {@link comparator} for lodash-based comparison (deprecated)
|
|
144
|
+
* @see {@link https://github.com/epoberezkin/fast-deep-equal fast-deep-equal library}
|
|
145
|
+
*/
|
|
146
|
+
declare const deepEqual: (data1: any, data2: any) => boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Converts an object to a human-readable string representation
|
|
149
|
+
*
|
|
150
|
+
* Transforms JSON object to clean, readable text by removing braces, quotes, and
|
|
151
|
+
* adding spacing. Useful for logging, debugging, UI displays, and error messages.
|
|
152
|
+
*
|
|
153
|
+
* Transformation:
|
|
154
|
+
* 1. Stringify object to JSON
|
|
155
|
+
* 2. Remove braces `{}` and quotes `"`
|
|
156
|
+
* 3. Replace commas with comma+space for readability
|
|
157
|
+
*
|
|
158
|
+
* @param data - Object to format (must be JSON-serializable)
|
|
159
|
+
* @returns Human-readable string representation
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* // Simple object
|
|
164
|
+
* formatToReadableString({ name: 'Alice', age: 25 })
|
|
165
|
+
* // 'name: Alice, age: 25'
|
|
166
|
+
*
|
|
167
|
+
* // Multiple properties
|
|
168
|
+
* formatToReadableString({ id: 1, status: 'active', verified: true })
|
|
169
|
+
* // 'id: 1, status: active, verified: true'
|
|
170
|
+
*
|
|
171
|
+
* // Nested objects (flattened)
|
|
172
|
+
* formatToReadableString({ user: { name: 'Bob' }, role: 'admin' })
|
|
173
|
+
* // 'user: name: Bob, role: admin'
|
|
174
|
+
*
|
|
175
|
+
* // Empty object
|
|
176
|
+
* formatToReadableString({})
|
|
177
|
+
* // ''
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* // Real-world: Log request parameters
|
|
183
|
+
* function logApiRequest(endpoint: string, params: any) {
|
|
184
|
+
* const paramsStr = formatToReadableString(params)
|
|
185
|
+
* console.log(`API Request: ${endpoint} | Params: ${paramsStr}`)
|
|
186
|
+
* }
|
|
187
|
+
*
|
|
188
|
+
* logApiRequest('/users', { page: 1, limit: 20, role: 'admin' })
|
|
189
|
+
* // API Request: /users | Params: page: 1, limit: 20, role: admin
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* // Real-world: Display validation errors
|
|
195
|
+
* const errors = { email: 'Invalid format', password: 'Too short' }
|
|
196
|
+
* const message = `Validation failed: ${formatToReadableString(errors)}`
|
|
197
|
+
* console.log(message)
|
|
198
|
+
* // Validation failed: email: Invalid format, password: Too short
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // Real-world: Format metadata for display
|
|
204
|
+
* const metadata = {
|
|
205
|
+
* author: 'John Doe',
|
|
206
|
+
* created: '2024-01-01',
|
|
207
|
+
* tags: ['javascript', 'typescript']
|
|
208
|
+
* }
|
|
209
|
+
*
|
|
210
|
+
* const metadataDisplay = formatToReadableString(metadata)
|
|
211
|
+
* // 'author: John Doe, created: 2024-01-01, tags: javascript, typescript'
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @see {@link JSON.stringify} for full JSON serialization
|
|
215
|
+
*/
|
|
216
|
+
declare const formatToReadableString: (data: {
|
|
217
|
+
[key: string]: any;
|
|
218
|
+
}) => string;
|
|
219
|
+
/**
|
|
220
|
+
* Extracts only top-level primitive properties from an object
|
|
221
|
+
*
|
|
222
|
+
* Filters out nested objects, arrays, and functions, returning only primitive values
|
|
223
|
+
* (string, number, boolean, null, undefined, symbol). Useful for serialization,
|
|
224
|
+
* API payloads, and database operations.
|
|
225
|
+
*
|
|
226
|
+
* Included types: string, number, boolean, null, undefined, symbol
|
|
227
|
+
* Excluded types: object, array, function
|
|
228
|
+
*
|
|
229
|
+
* @param obj - Object from which to extract properties (null/undefined returns {})
|
|
230
|
+
* @returns New object containing only primitive top-level properties
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* // Mixed types object
|
|
235
|
+
* const user = {
|
|
236
|
+
* id: 123,
|
|
237
|
+
* name: 'Alice',
|
|
238
|
+
* email: 'alice@example.com',
|
|
239
|
+
* age: 25,
|
|
240
|
+
* active: true,
|
|
241
|
+
* metadata: { lastLogin: '2024-01-01' }, // Excluded (object)
|
|
242
|
+
* roles: ['admin', 'user'], // Excluded (array)
|
|
243
|
+
* save: () => {} // Excluded (function)
|
|
244
|
+
* }
|
|
245
|
+
*
|
|
246
|
+
* getShallowProperties(user)
|
|
247
|
+
* // { id: 123, name: 'Alice', email: 'alice@example.com', age: 25, active: true }
|
|
248
|
+
*
|
|
249
|
+
* // Only primitives
|
|
250
|
+
* const config = { host: 'localhost', port: 5432, ssl: false }
|
|
251
|
+
* getShallowProperties(config)
|
|
252
|
+
* // { host: 'localhost', port: 5432, ssl: false } (unchanged)
|
|
253
|
+
*
|
|
254
|
+
* // Null/undefined values preserved
|
|
255
|
+
* const partial = { a: 1, b: null, c: undefined, d: { nested: true } }
|
|
256
|
+
* getShallowProperties(partial)
|
|
257
|
+
* // { a: 1, b: null, c: undefined }
|
|
258
|
+
*
|
|
259
|
+
* // Empty/null input
|
|
260
|
+
* getShallowProperties({}) // {}
|
|
261
|
+
* getShallowProperties(null) // {}
|
|
262
|
+
* ```
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```typescript
|
|
266
|
+
* // Real-world: Prepare data for SQL insert (exclude nested objects)
|
|
267
|
+
* const formData = {
|
|
268
|
+
* firstName: 'John',
|
|
269
|
+
* lastName: 'Doe',
|
|
270
|
+
* email: 'john@example.com',
|
|
271
|
+
* age: 30,
|
|
272
|
+
* address: { street: '123 Main St', city: 'NYC' }, // Excluded
|
|
273
|
+
* preferences: { theme: 'dark' } // Excluded
|
|
274
|
+
* }
|
|
275
|
+
*
|
|
276
|
+
* const insertData = getShallowProperties(formData)
|
|
277
|
+
* // { firstName: 'John', lastName: 'Doe', email: 'john@example.com', age: 30 }
|
|
278
|
+
*
|
|
279
|
+
* // Now safe to insert into flat database table
|
|
280
|
+
* await db.insert('users', insertData)
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ```typescript
|
|
285
|
+
* // Real-world: Extract searchable fields for indexing
|
|
286
|
+
* const product = {
|
|
287
|
+
* sku: 'ABC123',
|
|
288
|
+
* name: 'Widget',
|
|
289
|
+
* price: 29.99,
|
|
290
|
+
* inStock: true,
|
|
291
|
+
* category: { id: 1, name: 'Electronics' }, // Excluded
|
|
292
|
+
* reviews: [{ rating: 5 }], // Excluded
|
|
293
|
+
* images: ['img1.jpg', 'img2.jpg'] // Excluded
|
|
294
|
+
* }
|
|
295
|
+
*
|
|
296
|
+
* const searchableFields = getShallowProperties(product)
|
|
297
|
+
* // { sku: 'ABC123', name: 'Widget', price: 29.99, inStock: true }
|
|
298
|
+
*
|
|
299
|
+
* // Index only primitive fields for search
|
|
300
|
+
* searchIndex.add(product.sku, searchableFields)
|
|
301
|
+
* ```
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* // Real-world: Extract flat properties for CSV export
|
|
306
|
+
* const users = [
|
|
307
|
+
* {
|
|
308
|
+
* id: 1,
|
|
309
|
+
* name: 'Alice',
|
|
310
|
+
* email: 'alice@example.com',
|
|
311
|
+
* profile: { bio: 'Developer' },
|
|
312
|
+
* tags: ['admin']
|
|
313
|
+
* },
|
|
314
|
+
* {
|
|
315
|
+
* id: 2,
|
|
316
|
+
* name: 'Bob',
|
|
317
|
+
* email: 'bob@example.com',
|
|
318
|
+
* profile: { bio: 'Designer' },
|
|
319
|
+
* tags: ['user']
|
|
320
|
+
* }
|
|
321
|
+
* ]
|
|
322
|
+
*
|
|
323
|
+
* const csvData = users.map(getShallowProperties)
|
|
324
|
+
* // [
|
|
325
|
+
* // { id: 1, name: 'Alice', email: 'alice@example.com' },
|
|
326
|
+
* // { id: 2, name: 'Bob', email: 'bob@example.com' }
|
|
327
|
+
* // ]
|
|
328
|
+
* // Now safe to convert to CSV
|
|
329
|
+
* ```
|
|
330
|
+
*
|
|
331
|
+
* @see {@link calculateDifferences} for comparing objects
|
|
332
|
+
* @see {@link deepEqual} for deep comparison including nested objects
|
|
333
|
+
*/
|
|
334
|
+
declare const getShallowProperties: (obj: any) => any;
|
|
335
|
+
/**
|
|
336
|
+
* Calculates differences between two objects
|
|
337
|
+
*
|
|
338
|
+
* Compares two objects and returns only the properties that differ. Useful for
|
|
339
|
+
* change tracking, audit logs, delta updates, and optimistic UI updates.
|
|
340
|
+
*
|
|
341
|
+
* Special features:
|
|
342
|
+
* - Date comparison: Compares dates ignoring milliseconds (tolerance-based)
|
|
343
|
+
* - Shallow comparison: Only checks top-level properties
|
|
344
|
+
* - One-way diff: Returns changed properties from newObj (not deletions)
|
|
345
|
+
*
|
|
346
|
+
* @param oldObj - Original object to compare against (baseline)
|
|
347
|
+
* @param newObj - New object to compare (current state)
|
|
348
|
+
* @returns Object containing only properties that changed in newObj
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* // Simple property changes
|
|
353
|
+
* const old = { name: 'Alice', age: 25, city: 'NYC' }
|
|
354
|
+
* const updated = { name: 'Alice', age: 26, city: 'NYC' }
|
|
355
|
+
*
|
|
356
|
+
* calculateDifferences(old, updated)
|
|
357
|
+
* // { age: 26 } - only changed property
|
|
358
|
+
*
|
|
359
|
+
* // Multiple changes
|
|
360
|
+
* const old2 = { a: 1, b: 2, c: 3 }
|
|
361
|
+
* const new2 = { a: 1, b: 999, c: 3 }
|
|
362
|
+
* calculateDifferences(old2, new2)
|
|
363
|
+
* // { b: 999 }
|
|
364
|
+
*
|
|
365
|
+
* // No changes
|
|
366
|
+
* const old3 = { x: 10 }
|
|
367
|
+
* const new3 = { x: 10 }
|
|
368
|
+
* calculateDifferences(old3, new3)
|
|
369
|
+
* // {} - empty object
|
|
370
|
+
*
|
|
371
|
+
* // Date comparison (ignores milliseconds)
|
|
372
|
+
* const oldDate = { timestamp: new Date('2024-01-01T10:00:00.123Z') }
|
|
373
|
+
* const newDate = { timestamp: new Date('2024-01-01T10:00:00.456Z') }
|
|
374
|
+
* calculateDifferences(oldDate, newDate)
|
|
375
|
+
* // {} - dates considered equal (same second)
|
|
376
|
+
* ```
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```typescript
|
|
380
|
+
* // Real-world: Track form changes for audit log
|
|
381
|
+
* const originalUser = {
|
|
382
|
+
* name: 'John Doe',
|
|
383
|
+
* email: 'john@example.com',
|
|
384
|
+
* role: 'user',
|
|
385
|
+
* lastLogin: new Date('2024-01-01')
|
|
386
|
+
* }
|
|
387
|
+
*
|
|
388
|
+
* const updatedUser = {
|
|
389
|
+
* name: 'John Doe',
|
|
390
|
+
* email: 'john.doe@company.com', // Changed
|
|
391
|
+
* role: 'admin', // Changed
|
|
392
|
+
* lastLogin: new Date('2024-01-01')
|
|
393
|
+
* }
|
|
394
|
+
*
|
|
395
|
+
* const changes = calculateDifferences(originalUser, updatedUser)
|
|
396
|
+
* console.log('User changes:', changes)
|
|
397
|
+
* // { email: 'john.doe@company.com', role: 'admin' }
|
|
398
|
+
*
|
|
399
|
+
* // Save to audit log
|
|
400
|
+
* auditLog.push({
|
|
401
|
+
* userId: user.id,
|
|
402
|
+
* timestamp: new Date(),
|
|
403
|
+
* changes: changes
|
|
404
|
+
* })
|
|
405
|
+
* ```
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* ```typescript
|
|
409
|
+
* // Real-world: Optimistic UI updates (send only changed fields)
|
|
410
|
+
* function updateUserProfile(userId: string, formData: any) {
|
|
411
|
+
* const originalData = getCurrentUserData(userId)
|
|
412
|
+
*
|
|
413
|
+
* // Only send changed fields to API
|
|
414
|
+
* const delta = calculateDifferences(originalData, formData)
|
|
415
|
+
*
|
|
416
|
+
* if (Object.keys(delta).length === 0) {
|
|
417
|
+
* console.log('✅ No changes to save')
|
|
418
|
+
* return
|
|
419
|
+
* }
|
|
420
|
+
*
|
|
421
|
+
* // Send PATCH request with only changed fields
|
|
422
|
+
* return api.patch(`/users/${userId}`, delta)
|
|
423
|
+
* }
|
|
424
|
+
* ```
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```typescript
|
|
428
|
+
* // Real-world: Configuration change detection
|
|
429
|
+
* const previousConfig = {
|
|
430
|
+
* database: { host: 'localhost', port: 5432 },
|
|
431
|
+
* cache: { ttl: 3600 },
|
|
432
|
+
* features: { darkMode: true }
|
|
433
|
+
* }
|
|
434
|
+
*
|
|
435
|
+
* const newConfig = {
|
|
436
|
+
* database: { host: 'prod-db.example.com', port: 5432 },
|
|
437
|
+
* cache: { ttl: 7200 },
|
|
438
|
+
* features: { darkMode: true }
|
|
439
|
+
* }
|
|
440
|
+
*
|
|
441
|
+
* const configChanges = calculateDifferences(previousConfig, newConfig)
|
|
442
|
+
* // {
|
|
443
|
+
* // database: { host: 'prod-db.example.com', port: 5432 },
|
|
444
|
+
* // cache: { ttl: 7200 }
|
|
445
|
+
* // }
|
|
446
|
+
*
|
|
447
|
+
* // Note: Returns entire nested object if any property changed
|
|
448
|
+
* if (configChanges.database) {
|
|
449
|
+
* console.log('⚠️ Database configuration changed - restart required')
|
|
450
|
+
* }
|
|
451
|
+
* ```
|
|
452
|
+
*
|
|
453
|
+
* @see {@link deepEqual} for full equality check
|
|
454
|
+
* @see {@link getShallowProperties} for extracting only primitive properties
|
|
455
|
+
*/
|
|
456
|
+
declare const calculateDifferences: (oldObj: any, newObj: any) => any;
|
|
457
|
+
/**
|
|
458
|
+
* Generates CRC32 hash from various input types
|
|
459
|
+
*
|
|
460
|
+
* Creates a 32-bit cyclic redundancy check (CRC32) hash as hexadecimal string.
|
|
461
|
+
* Fast, deterministic fingerprinting for data integrity, caching, and change detection.
|
|
462
|
+
*
|
|
463
|
+
* Supported types:
|
|
464
|
+
* - String: Direct hash
|
|
465
|
+
* - Buffer/Uint8Array/ArrayBuffer: Binary hash
|
|
466
|
+
* - Number: Converts to string then hash
|
|
467
|
+
* - Boolean: 'true'/'false' then hash
|
|
468
|
+
* - Object/Array: JSON.stringify then hash
|
|
469
|
+
* - null/undefined: Hash of '-'
|
|
470
|
+
*
|
|
471
|
+
* Use cases: Content fingerprinting, ETags, cache keys, data deduplication
|
|
472
|
+
*
|
|
473
|
+
* ⚠️ NOTE: CRC32 is NOT cryptographically secure. Use for checksums, not security.
|
|
474
|
+
*
|
|
475
|
+
* @param str - Input data of any type (string, Buffer, object, array, primitive)
|
|
476
|
+
* @returns CRC32 hash as hexadecimal string (8 characters)
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```typescript
|
|
480
|
+
* // String inputs
|
|
481
|
+
* generateCrcHash('hello') // '3610a686'
|
|
482
|
+
* generateCrcHash('Hello') // 'f7d18982' (case-sensitive)
|
|
483
|
+
* generateCrcHash('') // '0'
|
|
484
|
+
*
|
|
485
|
+
* // Numbers
|
|
486
|
+
* generateCrcHash(123) // '884863d2' (hashes '123')
|
|
487
|
+
* generateCrcHash(0) // 'f4dbdf21'
|
|
488
|
+
*
|
|
489
|
+
* // Booleans
|
|
490
|
+
* generateCrcHash(true) // 'cc2c5c10' (hashes 'true')
|
|
491
|
+
* generateCrcHash(false) // 'cc0c5c10' (hashes 'false')
|
|
492
|
+
*
|
|
493
|
+
* // Objects (deterministic)
|
|
494
|
+
* generateCrcHash({ a: 1, b: 2 }) // Same hash for same object
|
|
495
|
+
* generateCrcHash({ b: 2, a: 1 }) // Different hash (key order matters)
|
|
496
|
+
*
|
|
497
|
+
* // Arrays
|
|
498
|
+
* generateCrcHash([1, 2, 3]) // Consistent hash
|
|
499
|
+
*
|
|
500
|
+
* // null/undefined
|
|
501
|
+
* generateCrcHash(null) // '4e08bfb4' (hashes '-')
|
|
502
|
+
* generateCrcHash(undefined) // '4e08bfb4' (hashes '-')
|
|
503
|
+
* ```
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```typescript
|
|
507
|
+
* // Real-world: Generate ETag for HTTP caching
|
|
508
|
+
* function generateETag(content: string): string {
|
|
509
|
+
* const hash = generateCrcHash(content)
|
|
510
|
+
* return `"${hash}"`
|
|
511
|
+
* }
|
|
512
|
+
*
|
|
513
|
+
* const html = '<html><body>Hello World</body></html>'
|
|
514
|
+
* const etag = generateETag(html)
|
|
515
|
+
* // "a3c2f1b8"
|
|
516
|
+
*
|
|
517
|
+
* // Client sends: If-None-Match: "a3c2f1b8"
|
|
518
|
+
* // Server compares ETags, returns 304 Not Modified if match
|
|
519
|
+
* ```
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```typescript
|
|
523
|
+
* // Real-world: Content-based cache key
|
|
524
|
+
* const cache = new Map<string, any>()
|
|
525
|
+
*
|
|
526
|
+
* function cacheApiResponse(params: any, response: any) {
|
|
527
|
+
* const cacheKey = generateCrcHash(JSON.stringify(params))
|
|
528
|
+
* cache.set(cacheKey, response)
|
|
529
|
+
* }
|
|
530
|
+
*
|
|
531
|
+
* function getCachedResponse(params: any) {
|
|
532
|
+
* const cacheKey = generateCrcHash(JSON.stringify(params))
|
|
533
|
+
* return cache.get(cacheKey)
|
|
534
|
+
* }
|
|
535
|
+
*
|
|
536
|
+
* // Same params = same hash = cache hit
|
|
537
|
+
* cacheApiResponse({ userId: 123, page: 1 }, { data: [...] })
|
|
538
|
+
* const cached = getCachedResponse({ userId: 123, page: 1 })
|
|
539
|
+
* ```
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```typescript
|
|
543
|
+
* // Real-world: Detect duplicate content
|
|
544
|
+
* const seen = new Set<string>()
|
|
545
|
+
*
|
|
546
|
+
* function isDuplicate(content: string): boolean {
|
|
547
|
+
* const hash = generateCrcHash(content)
|
|
548
|
+
* if (seen.has(hash)) {
|
|
549
|
+
* return true
|
|
550
|
+
* }
|
|
551
|
+
* seen.add(hash)
|
|
552
|
+
* return false
|
|
553
|
+
* }
|
|
554
|
+
*
|
|
555
|
+
* isDuplicate('Hello') // false (first time)
|
|
556
|
+
* isDuplicate('World') // false
|
|
557
|
+
* isDuplicate('Hello') // true (duplicate!)
|
|
558
|
+
* ```
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```typescript
|
|
562
|
+
* // Real-world: File versioning/fingerprinting
|
|
563
|
+
* const fileContents = [
|
|
564
|
+
* { path: 'app.js', content: 'console.log("v1")' },
|
|
565
|
+
* { path: 'style.css', content: 'body { color: red; }' }
|
|
566
|
+
* ]
|
|
567
|
+
*
|
|
568
|
+
* const manifest = fileContents.map(file => ({
|
|
569
|
+
* path: file.path,
|
|
570
|
+
* hash: generateCrcHash(file.content),
|
|
571
|
+
* url: `${file.path}?v=${generateCrcHash(file.content)}`
|
|
572
|
+
* }))
|
|
573
|
+
*
|
|
574
|
+
* // [
|
|
575
|
+
* // { path: 'app.js', hash: 'a3c2f1b8', url: 'app.js?v=a3c2f1b8' },
|
|
576
|
+
* // { path: 'style.css', hash: 'b4d3e2c1', url: 'style.css?v=b4d3e2c1' }
|
|
577
|
+
* // ]
|
|
578
|
+
* // Cache-busting URLs change only when content changes
|
|
579
|
+
* ```
|
|
580
|
+
*
|
|
581
|
+
* @see {@link deepEqual} for comparing objects for equality
|
|
582
|
+
* @see {@link https://en.wikipedia.org/wiki/Cyclic_redundancy_check CRC32 Algorithm}
|
|
583
|
+
*/
|
|
584
|
+
declare const generateCrcHash: (str: string | Buffer | Uint8Array | any) => string;
|
|
585
|
+
/**
|
|
586
|
+
* Verifies if two variables have the same type
|
|
587
|
+
*
|
|
588
|
+
* Performs strict type comparison with special handling for arrays, typed arrays,
|
|
589
|
+
* plain objects, and primitives. Uses runtime type checking for accurate validation.
|
|
590
|
+
*
|
|
591
|
+
* Type detection hierarchy:
|
|
592
|
+
* 1. Arrays: Standard Array.isArray() check
|
|
593
|
+
* 2. Typed Arrays: Int8Array, Uint8Array, Float32Array, etc. (checks exact typed array class)
|
|
594
|
+
* 3. Plain Objects: Object literals (not class instances or built-in objects)
|
|
595
|
+
* 4. Primitives: typeof comparison (string, number, boolean, undefined, symbol)
|
|
596
|
+
*
|
|
597
|
+
* Special features:
|
|
598
|
+
* - Differentiates between arrays and typed arrays
|
|
599
|
+
* - Typed array class matching (Int8Array ≠ Uint8Array)
|
|
600
|
+
* - Plain object vs class instance detection
|
|
601
|
+
* - null/undefined handling
|
|
602
|
+
*
|
|
603
|
+
* @param sourceTarget - First value to check type
|
|
604
|
+
* @param destinationTarget - Second value to check type
|
|
605
|
+
* @returns True if both values have the same type, false otherwise
|
|
606
|
+
*
|
|
607
|
+
* @example
|
|
608
|
+
* ```typescript
|
|
609
|
+
* // Basic types - Primitives
|
|
610
|
+
* hasSameType('hello', 'world') // true (both string)
|
|
611
|
+
* hasSameType(42, 100) // true (both number)
|
|
612
|
+
* hasSameType(true, false) // true (both boolean)
|
|
613
|
+
* hasSameType('hello', 42) // false (string vs number)
|
|
614
|
+
* hasSameType(null, undefined) // false (different types)
|
|
615
|
+
* ```
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* ```typescript
|
|
619
|
+
* // Arrays and objects
|
|
620
|
+
* hasSameType([1, 2, 3], [4, 5]) // true (both arrays)
|
|
621
|
+
* hasSameType({ a: 1 }, { b: 2 }) // true (both plain objects)
|
|
622
|
+
* hasSameType([1, 2], { a: 1 }) // false (array vs object)
|
|
623
|
+
* hasSameType([], {}) // false (array vs object)
|
|
624
|
+
* ```
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* ```typescript
|
|
628
|
+
* // Typed arrays - Strict class matching
|
|
629
|
+
* const int8 = new Int8Array([1, 2, 3])
|
|
630
|
+
* const int8_2 = new Int8Array([4, 5])
|
|
631
|
+
* const uint8 = new Uint8Array([1, 2, 3])
|
|
632
|
+
* const float32 = new Float32Array([1.5, 2.5])
|
|
633
|
+
*
|
|
634
|
+
* hasSameType(int8, int8_2) // true (both Int8Array)
|
|
635
|
+
* hasSameType(int8, uint8) // false (Int8Array vs Uint8Array)
|
|
636
|
+
* hasSameType(uint8, float32) // false (Uint8Array vs Float32Array)
|
|
637
|
+
* hasSameType(int8, [1, 2, 3]) // false (typed array vs regular array)
|
|
638
|
+
* ```
|
|
639
|
+
*
|
|
640
|
+
* @example
|
|
641
|
+
* ```typescript
|
|
642
|
+
* // Real-world: Type-safe data merging
|
|
643
|
+
* function safeMerge<T>(source: T, updates: any): T | null {
|
|
644
|
+
* if (!hasSameType(source, updates)) {
|
|
645
|
+
* console.error('❌ Type mismatch: cannot merge incompatible types')
|
|
646
|
+
* return null
|
|
647
|
+
* }
|
|
648
|
+
*
|
|
649
|
+
* if (Array.isArray(source)) {
|
|
650
|
+
* return [...source, ...updates] as T
|
|
651
|
+
* }
|
|
652
|
+
*
|
|
653
|
+
* if (typeof source === 'object' && source !== null) {
|
|
654
|
+
* return { ...source, ...updates }
|
|
655
|
+
* }
|
|
656
|
+
*
|
|
657
|
+
* return updates // Replace primitive values
|
|
658
|
+
* }
|
|
659
|
+
*
|
|
660
|
+
* // Valid merges
|
|
661
|
+
* const user = { name: 'John', age: 30 }
|
|
662
|
+
* const updated = safeMerge(user, { age: 31, city: 'NYC' })
|
|
663
|
+
* // { name: 'John', age: 31, city: 'NYC' }
|
|
664
|
+
*
|
|
665
|
+
* // Type mismatch prevented
|
|
666
|
+
* const invalid = safeMerge(user, [1, 2, 3])
|
|
667
|
+
* // null (with error logged)
|
|
668
|
+
* ```
|
|
669
|
+
*
|
|
670
|
+
* @example
|
|
671
|
+
* ```typescript
|
|
672
|
+
* // Real-world: API response validation
|
|
673
|
+
* function validateResponseShape(expected: any, actual: any): boolean {
|
|
674
|
+
* // Check if response has the same structure
|
|
675
|
+
* if (!hasSameType(expected, actual)) {
|
|
676
|
+
* console.error('Invalid response type:', {
|
|
677
|
+
* expected: typeof expected,
|
|
678
|
+
* actual: typeof actual
|
|
679
|
+
* })
|
|
680
|
+
* return false
|
|
681
|
+
* }
|
|
682
|
+
*
|
|
683
|
+
* // Additional validation for objects/arrays
|
|
684
|
+
* if (typeof expected === 'object' && expected !== null) {
|
|
685
|
+
* for (const key of Object.keys(expected)) {
|
|
686
|
+
* if (!hasSameType(expected[key], actual[key])) {
|
|
687
|
+
* console.error(`Type mismatch at key "${key}"`)
|
|
688
|
+
* return false
|
|
689
|
+
* }
|
|
690
|
+
* }
|
|
691
|
+
* }
|
|
692
|
+
*
|
|
693
|
+
* return true
|
|
694
|
+
* }
|
|
695
|
+
*
|
|
696
|
+
* const expectedUser = {
|
|
697
|
+
* id: 0,
|
|
698
|
+
* name: '',
|
|
699
|
+
* active: false,
|
|
700
|
+
* tags: [] as string[]
|
|
701
|
+
* }
|
|
702
|
+
*
|
|
703
|
+
* const validResponse = {
|
|
704
|
+
* id: 123,
|
|
705
|
+
* name: 'Alice',
|
|
706
|
+
* active: true,
|
|
707
|
+
* tags: ['admin', 'verified']
|
|
708
|
+
* }
|
|
709
|
+
*
|
|
710
|
+
* validateResponseShape(expectedUser, validResponse) // true
|
|
711
|
+
*
|
|
712
|
+
* const invalidResponse = {
|
|
713
|
+
* id: '123', // ❌ string instead of number
|
|
714
|
+
* name: 'Alice',
|
|
715
|
+
* active: true,
|
|
716
|
+
* tags: ['admin']
|
|
717
|
+
* }
|
|
718
|
+
*
|
|
719
|
+
* validateResponseShape(expectedUser, invalidResponse) // false
|
|
720
|
+
* ```
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* ```typescript
|
|
724
|
+
* // Real-world: Buffer/TypedArray validation before processing
|
|
725
|
+
* function processImageBuffer(buffer: Uint8Array | Uint8ClampedArray): void {
|
|
726
|
+
* const validBufferTypes = [
|
|
727
|
+
* new Uint8Array(0),
|
|
728
|
+
* new Uint8ClampedArray(0)
|
|
729
|
+
* ]
|
|
730
|
+
*
|
|
731
|
+
* const isValidType = validBufferTypes.some(validType =>
|
|
732
|
+
* hasSameType(buffer, validType)
|
|
733
|
+
* )
|
|
734
|
+
*
|
|
735
|
+
* if (!isValidType) {
|
|
736
|
+
* throw new TypeError('Expected Uint8Array or Uint8ClampedArray for image data')
|
|
737
|
+
* }
|
|
738
|
+
*
|
|
739
|
+
* // Safe to process buffer
|
|
740
|
+
* console.log(`Processing ${buffer.length} bytes of image data`)
|
|
741
|
+
* }
|
|
742
|
+
*
|
|
743
|
+
* // Valid buffers
|
|
744
|
+
* const imageData = new Uint8ClampedArray([255, 0, 0, 255]) // RGBA pixel
|
|
745
|
+
* processImageBuffer(imageData) // ✅ Works
|
|
746
|
+
*
|
|
747
|
+
* // Invalid buffer type
|
|
748
|
+
* const float32Buffer = new Float32Array([1.0, 0.5])
|
|
749
|
+
* processImageBuffer(float32Buffer) // ❌ TypeError
|
|
750
|
+
* ```
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* ```typescript
|
|
754
|
+
* // Edge cases
|
|
755
|
+
* hasSameType(null, null) // true (both null)
|
|
756
|
+
* hasSameType(undefined, undefined) // true (both undefined)
|
|
757
|
+
* hasSameType(null, undefined) // false (different types)
|
|
758
|
+
* hasSameType(NaN, NaN) // true (both number)
|
|
759
|
+
* hasSameType(Infinity, -Infinity) // true (both number)
|
|
760
|
+
*
|
|
761
|
+
* // Class instances vs plain objects
|
|
762
|
+
* class User { name = 'John' }
|
|
763
|
+
* const userInstance = new User()
|
|
764
|
+
* const plainUser = { name: 'John' }
|
|
765
|
+
* hasSameType(userInstance, plainUser) // false (class instance vs plain object)
|
|
766
|
+
*
|
|
767
|
+
* // Functions
|
|
768
|
+
* const fn1 = () => {}
|
|
769
|
+
* const fn2 = function() {}
|
|
770
|
+
* hasSameType(fn1, fn2) // true (both functions)
|
|
771
|
+
* ```
|
|
772
|
+
*
|
|
773
|
+
* @see {@link deepEqual} for value comparison (not just type)
|
|
774
|
+
* @see {@link isArray} for array checking
|
|
775
|
+
* @see {@link isPlainObject} for plain object detection
|
|
776
|
+
*/
|
|
777
|
+
declare const hasSameType: (sourceTarget: any, destinationTarget: any) => boolean;
|
|
778
|
+
/**
|
|
779
|
+
* Updates array elements that match search criteria
|
|
780
|
+
*
|
|
781
|
+
* Finds all elements matching the search criteria and merges update object into them.
|
|
782
|
+
* Mutates the original array. Useful for batch updates on filtered data.
|
|
783
|
+
*
|
|
784
|
+
* Algorithm:
|
|
785
|
+
* 1. Filter array to find elements matching objSearch
|
|
786
|
+
* 2. For each match, merge objUpd properties using Object.assign
|
|
787
|
+
* 3. Return the mutated array
|
|
788
|
+
*
|
|
789
|
+
* @param data - Array to update (will be mutated)
|
|
790
|
+
* @param objUpd - Object with properties to merge into matching elements
|
|
791
|
+
* @param objSearch - Object with search criteria (all properties must match)
|
|
792
|
+
* @returns The mutated array with updated elements
|
|
793
|
+
*
|
|
794
|
+
* @example
|
|
795
|
+
* ```typescript
|
|
796
|
+
* // Update all users with role 'user' to 'member'
|
|
797
|
+
* const users = [
|
|
798
|
+
* { id: 1, name: 'Alice', role: 'user', active: true },
|
|
799
|
+
* { id: 2, name: 'Bob', role: 'admin', active: true },
|
|
800
|
+
* { id: 3, name: 'Charlie', role: 'user', active: false }
|
|
801
|
+
* ]
|
|
802
|
+
*
|
|
803
|
+
* updateArrayElementsBy(users, { role: 'member' }, { role: 'user' })
|
|
804
|
+
* // users is now:
|
|
805
|
+
* // [
|
|
806
|
+
* // { id: 1, name: 'Alice', role: 'member', active: true },
|
|
807
|
+
* // { id: 2, name: 'Bob', role: 'admin', active: true },
|
|
808
|
+
* // { id: 3, name: 'Charlie', role: 'member', active: false }
|
|
809
|
+
* // ]
|
|
810
|
+
*
|
|
811
|
+
* // Update multiple properties
|
|
812
|
+
* const products = [
|
|
813
|
+
* { sku: 'A1', status: 'draft', published: false },
|
|
814
|
+
* { sku: 'A2', status: 'draft', published: false },
|
|
815
|
+
* { sku: 'B1', status: 'active', published: true }
|
|
816
|
+
* ]
|
|
817
|
+
*
|
|
818
|
+
* updateArrayElementsBy(
|
|
819
|
+
* products,
|
|
820
|
+
* { status: 'active', published: true },
|
|
821
|
+
* { status: 'draft' }
|
|
822
|
+
* )
|
|
823
|
+
* // All draft products now active and published
|
|
824
|
+
* ```
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* ```typescript
|
|
828
|
+
* // Real-world: Bulk activate pending users
|
|
829
|
+
* const pendingUsers = [
|
|
830
|
+
* { email: 'user1@example.com', status: 'pending', verified: false },
|
|
831
|
+
* { email: 'user2@example.com', status: 'pending', verified: false },
|
|
832
|
+
* { email: 'user3@example.com', status: 'active', verified: true }
|
|
833
|
+
* ]
|
|
834
|
+
*
|
|
835
|
+
* // Activate all pending users
|
|
836
|
+
* updateArrayElementsBy(
|
|
837
|
+
* pendingUsers,
|
|
838
|
+
* { status: 'active', verified: true, activatedAt: new Date() },
|
|
839
|
+
* { status: 'pending' }
|
|
840
|
+
* )
|
|
841
|
+
*
|
|
842
|
+
* console.log(pendingUsers.filter(u => u.status === 'active').length)
|
|
843
|
+
* // 3 (all users now active)
|
|
844
|
+
* ```
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* ```typescript
|
|
848
|
+
* // Real-world: Mark completed tasks as archived
|
|
849
|
+
* const tasks = [
|
|
850
|
+
* { id: 1, title: 'Task 1', completed: true, archived: false },
|
|
851
|
+
* { id: 2, title: 'Task 2', completed: false, archived: false },
|
|
852
|
+
* { id: 3, title: 'Task 3', completed: true, archived: false }
|
|
853
|
+
* ]
|
|
854
|
+
*
|
|
855
|
+
* updateArrayElementsBy(
|
|
856
|
+
* tasks,
|
|
857
|
+
* { archived: true, archivedAt: new Date() },
|
|
858
|
+
* { completed: true }
|
|
859
|
+
* )
|
|
860
|
+
*
|
|
861
|
+
* const archivedCount = tasks.filter(t => t.archived).length
|
|
862
|
+
* console.log(`Archived ${archivedCount} completed tasks`)
|
|
863
|
+
* ```
|
|
864
|
+
*
|
|
865
|
+
* @see {@link updateArrayElementById} for updating single element by ID
|
|
866
|
+
* @see {@link deleteArrayElementsBy} for deleting elements by criteria
|
|
867
|
+
*/
|
|
868
|
+
declare const updateArrayElementsBy: (data: any[], objUpd: any, objSearch: any) => any[];
|
|
869
|
+
/**
|
|
870
|
+
* Updates a single array element by its ID field
|
|
871
|
+
*
|
|
872
|
+
* Finds element by matching ID field value and replaces entire element with new object.
|
|
873
|
+
* Mutates the original array. Use for updating single records by primary key.
|
|
874
|
+
*
|
|
875
|
+
* Algorithm:
|
|
876
|
+
* 1. Find index of element where element[idField] === objUpd[idField]
|
|
877
|
+
* 2. If found, replace entire element with objUpd
|
|
878
|
+
* 3. If not found, array remains unchanged
|
|
879
|
+
*
|
|
880
|
+
* @param data - Array to update (will be mutated)
|
|
881
|
+
* @param objUpd - New object to replace the found element (must contain idField)
|
|
882
|
+
* @param idField - Name of field to use as identifier (default: 'id')
|
|
883
|
+
* @returns void (modifies array in-place)
|
|
884
|
+
*
|
|
885
|
+
* @example
|
|
886
|
+
* ```typescript
|
|
887
|
+
* // Update user by ID
|
|
888
|
+
* const users = [
|
|
889
|
+
* { id: 1, name: 'Alice', email: 'alice@example.com' },
|
|
890
|
+
* { id: 2, name: 'Bob', email: 'bob@example.com' },
|
|
891
|
+
* { id: 3, name: 'Charlie', email: 'charlie@example.com' }
|
|
892
|
+
* ]
|
|
893
|
+
*
|
|
894
|
+
* updateArrayElementById(
|
|
895
|
+
* users,
|
|
896
|
+
* { id: 2, name: 'Robert', email: 'robert@example.com', verified: true },
|
|
897
|
+
* 'id'
|
|
898
|
+
* )
|
|
899
|
+
* // users[1] is now: { id: 2, name: 'Robert', email: 'robert@example.com', verified: true }
|
|
900
|
+
*
|
|
901
|
+
* // ID not found - no change
|
|
902
|
+
* updateArrayElementById(users, { id: 999, name: 'Unknown' }, 'id')
|
|
903
|
+
* // users array unchanged
|
|
904
|
+
*
|
|
905
|
+
* // Custom ID field
|
|
906
|
+
* const products = [
|
|
907
|
+
* { sku: 'ABC123', name: 'Widget', price: 10 },
|
|
908
|
+
* { sku: 'DEF456', name: 'Gadget', price: 20 }
|
|
909
|
+
* ]
|
|
910
|
+
*
|
|
911
|
+
* updateArrayElementById(
|
|
912
|
+
* products,
|
|
913
|
+
* { sku: 'ABC123', name: 'Super Widget', price: 15 },
|
|
914
|
+
* 'sku'
|
|
915
|
+
* )
|
|
916
|
+
* // products[0] is now: { sku: 'ABC123', name: 'Super Widget', price: 15 }
|
|
917
|
+
* ```
|
|
918
|
+
*
|
|
919
|
+
* @example
|
|
920
|
+
* ```typescript
|
|
921
|
+
* // Real-world: Update cached user after API response
|
|
922
|
+
* const userCache = [
|
|
923
|
+
* { id: 1, name: 'Alice', role: 'user' },
|
|
924
|
+
* { id: 2, name: 'Bob', role: 'admin' },
|
|
925
|
+
* ]
|
|
926
|
+
*
|
|
927
|
+
* async function updateUser(userId: number, updates: any) {
|
|
928
|
+
* // API call
|
|
929
|
+
* const response = await api.patch(`/users/${userId}`, updates)
|
|
930
|
+
*
|
|
931
|
+
* // Update local cache with full response
|
|
932
|
+
* updateArrayElementById(userCache, response.data, 'id')
|
|
933
|
+
*
|
|
934
|
+
* console.log('✅ Cache updated')
|
|
935
|
+
* }
|
|
936
|
+
* ```
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* ```typescript
|
|
940
|
+
* // Real-world: Replace product in shopping cart
|
|
941
|
+
* const cart = [
|
|
942
|
+
* { productId: 'P1', name: 'Laptop', qty: 1, price: 1000 },
|
|
943
|
+
* { productId: 'P2', name: 'Mouse', qty: 2, price: 25 }
|
|
944
|
+
* ]
|
|
945
|
+
*
|
|
946
|
+
* function updateCartItem(updatedItem: any) {
|
|
947
|
+
* updateArrayElementById(cart, updatedItem, 'productId')
|
|
948
|
+
* recalculateTotal()
|
|
949
|
+
* }
|
|
950
|
+
*
|
|
951
|
+
* // User changes laptop quantity
|
|
952
|
+
* updateCartItem({ productId: 'P1', name: 'Laptop', qty: 2, price: 1000 })
|
|
953
|
+
* ```
|
|
954
|
+
*
|
|
955
|
+
* @see {@link updateArrayElementsBy} for updating multiple elements by criteria
|
|
956
|
+
* @see {@link deleteArrayElementsBy} for deleting elements
|
|
957
|
+
*/
|
|
958
|
+
declare const updateArrayElementById: (data: any[], objUpd: any, idField: string) => void;
|
|
959
|
+
/**
|
|
960
|
+
* Removes array elements that match search criteria
|
|
961
|
+
*
|
|
962
|
+
* Filters out elements matching all properties in the search object.
|
|
963
|
+
* Mutates the original array. Useful for batch deletions based on criteria.
|
|
964
|
+
*
|
|
965
|
+
* Algorithm:
|
|
966
|
+
* 1. Pick properties from each element matching objSearch keys
|
|
967
|
+
* 2. Deep compare picked properties with objSearch
|
|
968
|
+
* 3. Remove element if all properties match
|
|
969
|
+
* 4. Return the mutated array
|
|
970
|
+
*
|
|
971
|
+
* @param data - Array to modify (will be mutated)
|
|
972
|
+
* @param objSearch - Object with search criteria (all properties must match for deletion)
|
|
973
|
+
* @returns The mutated array with matching elements removed
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* ```typescript
|
|
977
|
+
* // Delete users with role 'guest'
|
|
978
|
+
* const users = [
|
|
979
|
+
* { id: 1, name: 'Alice', role: 'admin' },
|
|
980
|
+
* { id: 2, name: 'Bob', role: 'guest' },
|
|
981
|
+
* { id: 3, name: 'Charlie', role: 'guest' },
|
|
982
|
+
* { id: 4, name: 'Dave', role: 'user' }
|
|
983
|
+
* ]
|
|
984
|
+
*
|
|
985
|
+
* deleteArrayElementsBy(users, { role: 'guest' })
|
|
986
|
+
* // users is now: [
|
|
987
|
+
* // { id: 1, name: 'Alice', role: 'admin' },
|
|
988
|
+
* // { id: 4, name: 'Dave', role: 'user' }
|
|
989
|
+
* // ]
|
|
990
|
+
*
|
|
991
|
+
* // Multiple criteria (AND condition)
|
|
992
|
+
* const tasks = [
|
|
993
|
+
* { id: 1, status: 'done', archived: true },
|
|
994
|
+
* { id: 2, status: 'done', archived: false },
|
|
995
|
+
* { id: 3, status: 'pending', archived: false }
|
|
996
|
+
* ]
|
|
997
|
+
*
|
|
998
|
+
* deleteArrayElementsBy(tasks, { status: 'done', archived: true })
|
|
999
|
+
* // Removes only tasks that are BOTH done AND archived
|
|
1000
|
+
* ```
|
|
1001
|
+
*
|
|
1002
|
+
* @example
|
|
1003
|
+
* ```typescript
|
|
1004
|
+
* // Real-world: Clean up expired sessions
|
|
1005
|
+
* const sessions = [
|
|
1006
|
+
* { sessionId: 'abc', userId: 1, expired: false },
|
|
1007
|
+
* { sessionId: 'def', userId: 2, expired: true },
|
|
1008
|
+
* { sessionId: 'ghi', userId: 3, expired: true },
|
|
1009
|
+
* { sessionId: 'jkl', userId: 4, expired: false }
|
|
1010
|
+
* ]
|
|
1011
|
+
*
|
|
1012
|
+
* // Remove all expired sessions
|
|
1013
|
+
* deleteArrayElementsBy(sessions, { expired: true })
|
|
1014
|
+
*
|
|
1015
|
+
* console.log(`Active sessions: ${sessions.length}`)
|
|
1016
|
+
* // Active sessions: 2
|
|
1017
|
+
* ```
|
|
1018
|
+
*
|
|
1019
|
+
* @example
|
|
1020
|
+
* ```typescript
|
|
1021
|
+
* // Real-world: Remove cancelled orders from pending list
|
|
1022
|
+
* const orders = [
|
|
1023
|
+
* { orderId: 'O1', status: 'pending', cancelled: false },
|
|
1024
|
+
* { orderId: 'O2', status: 'pending', cancelled: true },
|
|
1025
|
+
* { orderId: 'O3', status: 'shipped', cancelled: false },
|
|
1026
|
+
* { orderId: 'O4', status: 'pending', cancelled: true }
|
|
1027
|
+
* ]
|
|
1028
|
+
*
|
|
1029
|
+
* // Clean up cancelled pending orders
|
|
1030
|
+
* deleteArrayElementsBy(orders, { status: 'pending', cancelled: true })
|
|
1031
|
+
*
|
|
1032
|
+
* // orders now only has valid pending and shipped orders
|
|
1033
|
+
* console.log(orders.length) // 2
|
|
1034
|
+
* ```
|
|
1035
|
+
*
|
|
1036
|
+
* @example
|
|
1037
|
+
* ```typescript
|
|
1038
|
+
* // Real-world: Clear failed upload queue
|
|
1039
|
+
* const uploadQueue = [
|
|
1040
|
+
* { fileId: 'F1', status: 'uploading', retries: 0 },
|
|
1041
|
+
* { fileId: 'F2', status: 'failed', retries: 3 },
|
|
1042
|
+
* { fileId: 'F3', status: 'failed', retries: 3 },
|
|
1043
|
+
* { fileId: 'F4', status: 'completed', retries: 0 }
|
|
1044
|
+
* ]
|
|
1045
|
+
*
|
|
1046
|
+
* // Remove permanently failed uploads (max retries reached)
|
|
1047
|
+
* deleteArrayElementsBy(uploadQueue, { status: 'failed', retries: 3 })
|
|
1048
|
+
*
|
|
1049
|
+
* console.log(`Remaining in queue: ${uploadQueue.length}`)
|
|
1050
|
+
* // Remaining in queue: 2 (uploading + completed)
|
|
1051
|
+
* ```
|
|
1052
|
+
*
|
|
1053
|
+
* @see {@link updateArrayElementsBy} for updating elements by criteria
|
|
1054
|
+
* @see {@link updateArrayElementById} for updating single element by ID
|
|
1055
|
+
*/
|
|
1056
|
+
declare const deleteArrayElementsBy: (data: any[], objSearch: any) => any[];
|
|
1057
|
+
/**
|
|
1058
|
+
* Sets a value at a deep path in an object using dot notation
|
|
1059
|
+
*
|
|
1060
|
+
* Creates intermediate objects/arrays as needed. Supports nested paths
|
|
1061
|
+
* and array indices. Mutates the original object.
|
|
1062
|
+
*
|
|
1063
|
+
* @param obj - Object to modify (will be mutated)
|
|
1064
|
+
* @param path - Dot-notation path (e.g., 'database.connection.timeout')
|
|
1065
|
+
* @param value - Value to set at the path
|
|
1066
|
+
* @returns The modified object (same reference as input)
|
|
1067
|
+
*
|
|
1068
|
+
* @example
|
|
1069
|
+
* ```typescript
|
|
1070
|
+
* // Simple nested path
|
|
1071
|
+
* const config = {}
|
|
1072
|
+
* setDeepValue(config, 'database.host', 'localhost')
|
|
1073
|
+
* // config = { database: { host: 'localhost' } }
|
|
1074
|
+
*
|
|
1075
|
+
* // Multi-level nesting
|
|
1076
|
+
* const obj = {}
|
|
1077
|
+
* setDeepValue(obj, 'app.server.port', 3000)
|
|
1078
|
+
* // obj = { app: { server: { port: 3000 } } }
|
|
1079
|
+
*
|
|
1080
|
+
* // Array indices
|
|
1081
|
+
* const data = { users: [] }
|
|
1082
|
+
* setDeepValue(data, 'users.0.name', 'Alice')
|
|
1083
|
+
* // data = { users: [{ name: 'Alice' }] }
|
|
1084
|
+
*
|
|
1085
|
+
* // Overwriting existing values
|
|
1086
|
+
* const settings = { database: { host: 'old' } }
|
|
1087
|
+
* setDeepValue(settings, 'database.host', 'new')
|
|
1088
|
+
* // settings = { database: { host: 'new' } }
|
|
1089
|
+
*
|
|
1090
|
+
* // Complex paths
|
|
1091
|
+
* const complex = {}
|
|
1092
|
+
* setDeepValue(complex, 'features.authentication.oauth.providers.0', 'google')
|
|
1093
|
+
* // complex = { features: { authentication: { oauth: { providers: ['google'] } } } }
|
|
1094
|
+
* ```
|
|
1095
|
+
*
|
|
1096
|
+
* @example
|
|
1097
|
+
* ```typescript
|
|
1098
|
+
* // Real-world: Dynamic configuration
|
|
1099
|
+
* const config = {}
|
|
1100
|
+
* const envVars = {
|
|
1101
|
+
* 'DATABASE_HOST': 'localhost',
|
|
1102
|
+
* 'DATABASE_PORT': '5432',
|
|
1103
|
+
* 'CACHE_TTL': '3600'
|
|
1104
|
+
* }
|
|
1105
|
+
*
|
|
1106
|
+
* // Convert flat env vars to nested config
|
|
1107
|
+
* setDeepValue(config, 'database.host', envVars.DATABASE_HOST)
|
|
1108
|
+
* setDeepValue(config, 'database.port', parseInt(envVars.DATABASE_PORT))
|
|
1109
|
+
* setDeepValue(config, 'cache.ttl', parseInt(envVars.CACHE_TTL))
|
|
1110
|
+
* // config = {
|
|
1111
|
+
* // database: { host: 'localhost', port: 5432 },
|
|
1112
|
+
* // cache: { ttl: 3600 }
|
|
1113
|
+
* // }
|
|
1114
|
+
* ```
|
|
1115
|
+
*/
|
|
1116
|
+
declare function setDeepValue<T = any>(obj: T, path: string, value: any): T;
|
|
1117
|
+
/**
|
|
1118
|
+
* Gets a value at a deep path in an object using dot notation
|
|
1119
|
+
*
|
|
1120
|
+
* Safely retrieves values from nested objects/arrays. Returns undefined
|
|
1121
|
+
* or a default value if path doesn't exist.
|
|
1122
|
+
*
|
|
1123
|
+
* @param obj - Object to read from
|
|
1124
|
+
* @param path - Dot-notation path (e.g., 'database.connection.timeout')
|
|
1125
|
+
* @param defaultValue - Value to return if path doesn't exist (default: undefined)
|
|
1126
|
+
* @returns Value at the path, or defaultValue if not found
|
|
1127
|
+
*
|
|
1128
|
+
* @example
|
|
1129
|
+
* ```typescript
|
|
1130
|
+
* // Simple nested access
|
|
1131
|
+
* const config = { database: { host: 'localhost' } }
|
|
1132
|
+
* getDeepValue(config, 'database.host') // 'localhost'
|
|
1133
|
+
*
|
|
1134
|
+
* // Non-existent path returns undefined
|
|
1135
|
+
* getDeepValue(config, 'database.port') // undefined
|
|
1136
|
+
*
|
|
1137
|
+
* // With default value
|
|
1138
|
+
* getDeepValue(config, 'database.port', 5432) // 5432
|
|
1139
|
+
*
|
|
1140
|
+
* // Array access
|
|
1141
|
+
* const data = { users: [{ name: 'Alice' }, { name: 'Bob' }] }
|
|
1142
|
+
* getDeepValue(data, 'users.0.name') // 'Alice'
|
|
1143
|
+
* getDeepValue(data, 'users.1.name') // 'Bob'
|
|
1144
|
+
*
|
|
1145
|
+
* // Deep paths
|
|
1146
|
+
* const app = { features: { auth: { enabled: true } } }
|
|
1147
|
+
* getDeepValue(app, 'features.auth.enabled') // true
|
|
1148
|
+
* getDeepValue(app, 'features.payments.enabled', false) // false (default)
|
|
1149
|
+
* ```
|
|
1150
|
+
*
|
|
1151
|
+
* @example
|
|
1152
|
+
* ```typescript
|
|
1153
|
+
* // Real-world: Safe config access
|
|
1154
|
+
* const config = {
|
|
1155
|
+
* database: { host: 'localhost' },
|
|
1156
|
+
* cache: { ttl: 3600 }
|
|
1157
|
+
* }
|
|
1158
|
+
*
|
|
1159
|
+
* const dbHost = getDeepValue(config, 'database.host', '127.0.0.1')
|
|
1160
|
+
* const dbPort = getDeepValue(config, 'database.port', 5432)
|
|
1161
|
+
* const cacheTtl = getDeepValue(config, 'cache.ttl', 1800)
|
|
1162
|
+
* const redisHost = getDeepValue(config, 'redis.host', 'localhost')
|
|
1163
|
+
*
|
|
1164
|
+
* // All values are safely retrieved with fallbacks
|
|
1165
|
+
* ```
|
|
1166
|
+
*/
|
|
1167
|
+
declare function getDeepValue<T = any>(obj: any, path: string, defaultValue?: T): T | undefined;
|
|
1168
|
+
|
|
1169
|
+
declare const objects_calculateDifferences: typeof calculateDifferences;
|
|
1170
|
+
declare const objects_comparator: typeof comparator;
|
|
1171
|
+
declare const objects_deepEqual: typeof deepEqual;
|
|
1172
|
+
declare const objects_deleteArrayElementsBy: typeof deleteArrayElementsBy;
|
|
1173
|
+
declare const objects_formatToReadableString: typeof formatToReadableString;
|
|
1174
|
+
declare const objects_generateCrcHash: typeof generateCrcHash;
|
|
1175
|
+
declare const objects_getDeepValue: typeof getDeepValue;
|
|
1176
|
+
declare const objects_getShallowProperties: typeof getShallowProperties;
|
|
1177
|
+
declare const objects_hasSameType: typeof hasSameType;
|
|
1178
|
+
declare const objects_setDeepValue: typeof setDeepValue;
|
|
1179
|
+
declare const objects_updateArrayElementById: typeof updateArrayElementById;
|
|
1180
|
+
declare const objects_updateArrayElementsBy: typeof updateArrayElementsBy;
|
|
1181
|
+
declare namespace objects {
|
|
1182
|
+
export { objects_calculateDifferences as calculateDifferences, objects_comparator as comparator, objects_deepEqual as deepEqual, objects_deleteArrayElementsBy as deleteArrayElementsBy, objects_formatToReadableString as formatToReadableString, objects_generateCrcHash as generateCrcHash, objects_getDeepValue as getDeepValue, objects_getShallowProperties as getShallowProperties, objects_hasSameType as hasSameType, objects_setDeepValue as setDeepValue, objects_updateArrayElementById as updateArrayElementById, objects_updateArrayElementsBy as updateArrayElementsBy };
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
export { calculateDifferences as a, generateCrcHash as b, comparator as c, deepEqual as d, updateArrayElementById as e, formatToReadableString as f, getShallowProperties as g, hasSameType as h, deleteArrayElementsBy as i, getDeepValue as j, objects as o, setDeepValue as s, updateArrayElementsBy as u };
|