1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
-
3
1
import { InterpolatableTranslationObject } from './translate.service' ;
4
2
5
3
/**
@@ -15,38 +13,43 @@ import { InterpolatableTranslationObject } from './translate.service';
15
13
* @param o2 Object or value to compare.
16
14
* @returns true if arguments are equal.
17
15
*/
18
- export function equals ( o1 : any , o2 : any ) : boolean {
16
+ export function equals ( o1 : unknown , o2 : unknown ) : boolean {
19
17
if ( o1 === o2 ) return true ;
20
18
if ( o1 === null || o2 === null ) return false ;
21
19
if ( o1 !== o1 && o2 !== o2 ) return true ; // NaN === NaN
20
+
22
21
const t1 = typeof o1 , t2 = typeof o2 ;
23
- let length : number , key : any , keySet : any ;
22
+ let length : number ;
23
+
24
24
if ( t1 == t2 && t1 == 'object' ) {
25
25
if ( Array . isArray ( o1 ) ) {
26
26
if ( ! Array . isArray ( o2 ) ) return false ;
27
27
if ( ( length = o1 . length ) == o2 . length ) {
28
- for ( key = 0 ; key < length ; key ++ ) {
28
+ for ( let key = 0 ; key < length ; key ++ ) {
29
29
if ( ! equals ( o1 [ key ] , o2 [ key ] ) ) return false ;
30
30
}
31
31
return true ;
32
32
}
33
- } else {
33
+ }
34
+ else {
34
35
if ( Array . isArray ( o2 ) ) {
35
36
return false ;
36
37
}
37
- keySet = Object . create ( null ) ;
38
- for ( key in o1 ) {
39
- if ( ! equals ( o1 [ key ] , o2 [ key ] ) ) {
40
- return false ;
38
+ if ( isDict ( o1 ) && isDict ( o2 ) ) {
39
+ const keySet = Object . create ( null ) ;
40
+ for ( const key in o1 ) {
41
+ if ( ! equals ( o1 [ key ] , o2 [ key ] ) ) {
42
+ return false ;
43
+ }
44
+ keySet [ key ] = true ;
41
45
}
42
- keySet [ key ] = true ;
43
- }
44
- for ( key in o2 ) {
45
- if ( ! ( key in keySet ) && typeof o2 [ key ] !== 'undefined' ) {
46
- return false ;
46
+ for ( const key in o2 ) {
47
+ if ( ! ( key in keySet ) && typeof o2 [ key ] !== 'undefined' ) {
48
+ return false ;
49
+ }
47
50
}
51
+ return true ;
48
52
}
49
- return true ;
50
53
}
51
54
}
52
55
return false ;
@@ -56,61 +59,59 @@ export function isDefinedAndNotNull<T>(value: T | null | undefined): value is T
56
59
return typeof value !== 'undefined' && value !== null ;
57
60
}
58
61
62
+ export function isDefined < T > ( value : T | null | undefined ) : value is ( T | null ) {
63
+ return value !== undefined ;
64
+ }
59
65
60
- export function isDict ( value : any ) : value is InterpolatableTranslationObject {
66
+ export function isDict ( value : unknown ) : value is InterpolatableTranslationObject {
61
67
return isObject ( value ) && ! isArray ( value ) && value !== null ;
62
68
}
63
69
64
-
65
- export function isObject ( value : any ) : value is Record < string , any > {
70
+ export function isObject ( value : unknown ) : value is Record < string , unknown > {
66
71
return typeof value === 'object' && value !== null ;
67
72
}
68
73
69
- export function isArray ( value : any ) : value is any [ ] {
74
+ export function isArray ( value : unknown ) : value is unknown [ ] {
70
75
return Array . isArray ( value ) ;
71
76
}
72
77
73
- export function isString ( value : any ) : value is string {
78
+ export function isString ( value : unknown ) : value is string {
74
79
return typeof value === 'string' ;
75
80
}
76
81
77
- export function isFunction ( value : any ) : boolean {
82
+ export function isFunction ( value : unknown ) : boolean {
78
83
return typeof value === "function"
79
84
}
80
85
81
- export function cloneDeep < T > ( obj : Readonly < T > ) : T
82
- {
83
- if ( obj === null || typeof obj !== "object" )
84
- {
85
- return obj ;
86
- }
87
-
88
- if ( Array . isArray ( obj ) ) {
89
- return obj . map ( ( item ) => cloneDeep ( item ) ) as unknown as T ;
86
+ function cloneDeep ( value : unknown ) : unknown {
87
+ if ( isArray ( value ) ) {
88
+ return value . map ( item => cloneDeep ( item ) ) ;
89
+ } else if ( isDict ( value ) ) {
90
+ const cloned : Record < string , unknown > = { } ;
91
+ Object . keys ( value ) . forEach ( key => {
92
+ cloned [ key ] = cloneDeep ( ( value as Record < string , unknown > ) [ key ] ) ;
93
+ } ) ;
94
+ return cloned ;
95
+ } else {
96
+ return value ;
90
97
}
91
-
92
- const clonedObj : Record < string , any > = { } ;
93
-
94
- Object . keys ( obj ) . forEach ( ( key ) => {
95
- clonedObj [ key ] = cloneDeep ( ( obj as Record < string , any > ) [ key ] ) ;
96
- } ) ;
97
-
98
- return clonedObj as T ;
99
98
}
100
99
101
- export function mergeDeep ( target : Readonly < any > , source : any ) : any {
102
- const output = cloneDeep ( target ) ;
103
-
100
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
101
+ export function mergeDeep ( target : Readonly < unknown > , source : Readonly < unknown > ) : any {
104
102
if ( ! isObject ( target ) )
105
103
{
106
104
return cloneDeep ( source )
107
105
}
108
106
109
- if ( isObject ( target ) && isObject ( source ) ) {
107
+ const output = cloneDeep ( target ) ;
108
+
109
+ if ( isObject ( output ) && isObject ( source ) ) {
110
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
110
111
Object . keys ( source ) . forEach ( ( key : any ) => {
111
112
if ( isDict ( source [ key ] ) ) {
112
113
if ( key in target ) {
113
- output [ key ] = mergeDeep ( target [ key ] , source [ key ] ) ;
114
+ output [ key ] = mergeDeep ( target [ key ] as Readonly < unknown > , source [ key ] ) ;
114
115
} else {
115
116
Object . assign ( output , { [ key ] : source [ key ] } ) ;
116
117
}
@@ -135,31 +136,51 @@ export function mergeDeep(target: Readonly<any>, source: any): any {
135
136
* @param key Dot-separated key path specifying the value to retrieve.
136
137
* @returns The value at the specified key path, or `undefined` if not found.
137
138
*/
138
- export function getValue ( target : any , key : string ) : any
139
+ export function getValue ( target : unknown , key : string ) : unknown
139
140
{
140
141
const keys = key . split ( "." ) ;
141
142
142
143
key = "" ;
143
144
do
144
145
{
145
146
key += keys . shift ( ) ;
146
- if (
147
- isDefinedAndNotNull ( target ) &&
148
- ( isDefinedAndNotNull ( target [ key ] ) || target [ key ] === null ) &&
149
- ( isDict ( target [ key ] ) || isArray ( target [ key ] ) || ! keys . length )
150
- )
147
+ const isLastKey = ! keys . length ;
148
+
149
+ if ( isDefinedAndNotNull ( target ) )
151
150
{
152
- target = target [ key ] ;
153
- key = "" ;
151
+ if (
152
+ isDict ( target ) &&
153
+ isDefined ( target [ key ] ) &&
154
+ ( isDict ( target [ key ] ) || isArray ( target [ key ] ) || isLastKey )
155
+ )
156
+ {
157
+ target = target [ key ] ;
158
+ key = "" ;
159
+ continue ;
160
+ }
161
+
162
+ if ( isArray ( target ) )
163
+ {
164
+ const index = parseInt ( key , 10 ) ;
165
+ if (
166
+ isDefined ( target [ index ] ) &&
167
+ ( isDict ( target [ index ] ) || isArray ( target [ index ] ) || isLastKey )
168
+ )
169
+ {
170
+ target = target [ index ] ;
171
+ key = "" ;
172
+ continue ;
173
+ }
174
+ }
154
175
}
155
- else if ( ! keys . length )
176
+
177
+ if ( isLastKey )
156
178
{
157
179
target = undefined ;
180
+ continue ;
158
181
}
159
- else
160
- {
161
- key += "." ;
162
- }
182
+ key += "." ;
183
+
163
184
} while ( keys . length ) ;
164
185
165
186
return target ;
@@ -174,22 +195,17 @@ export function getValue(target: any, key: string): any
174
195
* @param value to set
175
196
* @deprecated use insertValue() instead
176
197
*/
177
- export function setValue ( target : any , key : string , value : any ) : void {
178
- const keys = key . split ( '.' ) ;
179
- let current = target ;
198
+ export function setValue ( target : Record < string , unknown > , key : string , value : unknown ) : void {
199
+ const keys : string [ ] = key . split ( '.' ) ;
200
+ let current : Record < string , unknown > = target ;
180
201
181
202
for ( let i = 0 ; i < keys . length ; i ++ ) {
182
203
const key = keys [ i ] ;
183
204
184
- // If we're at the last key, set the value
185
205
if ( i === keys . length - 1 ) {
186
206
current [ key ] = value ;
187
207
} else {
188
- // If the key doesn't exist or isn't an object, create an empty object
189
- if ( ! current [ key ] || ! isDict ( current [ key ] ) ) {
190
- current [ key ] = { } ;
191
- }
192
- current = current [ key ] ;
208
+ current = ( current [ key ] && isDict ( current [ key ] ) ) ? current [ key ] : { } ;
193
209
}
194
210
}
195
211
}
@@ -204,12 +220,15 @@ export function setValue(target: any, key: string, value: any): void {
204
220
* @param key E.g. "a.b.c"
205
221
* @param value to set
206
222
*/
207
- export function insertValue ( target : Readonly < any > , key : string , value : any ) : any {
208
- return mergeDeep ( target , createNestedObject ( key , value ) ) ;
223
+ export function insertValue < T > ( target : Readonly < T > , key : string , value : unknown ) : T {
224
+ return mergeDeep ( target , createNestedObject ( key , value ) as Readonly < unknown > ) ;
209
225
}
210
226
211
227
212
228
213
- function createNestedObject ( dotSeparatedKey : string , value : any ) : Record < string , any > {
214
- return dotSeparatedKey . split ( '.' ) . reduceRight ( ( acc , key ) => ( { [ key ] : acc } ) , value ) ;
229
+ function createNestedObject ( dotSeparatedKey : string , value : unknown ) : Record < string , unknown > | unknown
230
+ {
231
+ return dotSeparatedKey
232
+ . split ( '.' )
233
+ . reduceRight < unknown > ( ( acc , key ) => ( { [ key ] : acc } ) , value ) ;
215
234
}
0 commit comments