• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

igoramadas / anyhow / 4896311387

05 May 2023 06:12PM UTC coverage: 94.052% (+4.7%) from 89.359%
4896311387

push

github

Igor Ramadas
Version 3.3.0.

324 of 353 branches covered (91.78%)

Branch coverage included in aggregate %.

435 of 454 relevant lines covered (95.81%)

3176.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.55
/src/utils.ts
1
// Anyhow: Utils (largely based on lodash.js)
2

3
import {defaultOptions} from "./types"
3✔
4

5
/**
6
 * Clone the passed object and return a new one.
7
 * @param obj The object to be cloned.
8
 * @param logErrors Log cloning failures? Defaults to false.
9
 * @param maxDepth Maximum depth to reach.
10
 * @param depth Current depth.
11
 */
12
export const cloneDeep = (obj: any, logErrors?: boolean, maxDepth?: number, depth?: number): any => {
3✔
13
    if (!obj) return obj
1,155✔
14
    if (!maxDepth) maxDepth = defaultOptions.maxDepth
1,152✔
15
    if (!depth) depth = 0
1,152✔
16

17
    let result
18

19
    try {
1,152✔
20
        if (isArray(obj)) {
1,152✔
21
            if (depth == maxDepth) {
20✔
22
                result = `[${obj.length}]`
1✔
23
            } else {
24
                result = []
19✔
25
                obj.forEach((element) => result.push(cloneDeep(element, logErrors, maxDepth, depth + 1)))
1,138✔
26
            }
27
        } else if (obj instanceof Object && !(obj instanceof Function)) {
1,132✔
28
            if (depth == maxDepth) {
1,015!
29
                result = obj.toString()
×
30
            } else {
31
                try {
1,015✔
32
                    result = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj)
1,015✔
33

34
                    if (isError(obj)) {
1,015!
35
                        result.stack = obj.stack
×
36
                    }
37
                } catch (innerEx) {
38
                    /* istanbul ignore next */
39
                    if (logErrors) {
40
                        console.warn("Utils.cloneDeep: Failed to clone constructor")
41
                        console.error(innerEx)
42
                    }
43
                }
44

45
                /* istanbul ignore if */
46
                if (!result) {
1,015✔
47
                    result = {}
48

49
                    for (let key in obj) {
50
                        if (key) result[key] = cloneDeep(obj[key], logErrors, maxDepth, depth + 1)
51
                    }
52
                }
53
            }
54
        } else {
55
            result = obj
117✔
56
        }
57
    } catch (ex) {
58
        /* istanbul ignore next */
59
        if (logErrors) {
60
            console.warn("Utils.cloneDeep: Failed to clone object")
61
            console.error(ex)
62
        }
63
    }
64

65
    return result
1,152✔
66
}
67

68
/**
69
 * Returns a deduplicated array.
70
 * @param arr Array to be deduplicated (immutable).
71
 */
72
export const dedupArray = (arr: any[]): any[] => {
3✔
73
    if (!arr || arr.length == 0) return arr
216!
74
    return arr.filter((item, index, self) => self.indexOf(item) == index)
1,169✔
75
}
76

77
/**
78
 * Flatten the passed array.
79
 * @param value Object or value.
80
 */
81
export const flattenArray = (array: any[], depth?: number, result?: any[]): any[] => {
3✔
82
    const length = array == null ? 0 : array.length
37✔
83
    if (!length) return []
37✔
84

85
    if (isNil(depth)) depth = 1 / 0
33✔
86
    if (isNil(result)) result = []
33✔
87

88
    const predicate = (value) => Array.isArray(value) || isArguments(value) || !!(value && value[Symbol.isConcatSpreadable])
3,367✔
89

90
    if (array == null) {
33!
91
        return result
×
92
    }
93

94
    for (const value of array) {
33✔
95
        if (depth > 0 && predicate(value)) {
3,367✔
96
            if (depth > 1) {
12!
97
                flattenArray(value, depth - 1, result)
12✔
98
            } else {
99
                result.push(...value)
×
100
            }
101
        } else {
102
            result[result.length] = value
3,355✔
103
        }
104
    }
105

106
    return result
33✔
107
}
108

109
/**
110
 * Get the passed object's tag.
111
 * @param value Object or value.
112
 */
113
export const getTag = (value: any) => {
3✔
114
    const toString = Object.prototype.toString
12,793✔
115

116
    if (value === null) {
12,793✔
117
        return "[object Null]"
1✔
118
    }
119
    if (value === undefined) {
12,792✔
120
        return "[object Undefined]"
1✔
121
    }
122

123
    if (value && value.constructor && value.constructor.name) {
12,791!
124
        return `[object ${value.constructor.name}]`
12,791✔
125
    }
126

127
    return toString.call(value)
×
128
}
129

130
/**
131
 * Get the current timestamp.
132
 */
133
export const getTimestamp = (): string => {
3✔
134
    const padLeft = (v) => {
14✔
135
        return v < 10 ? "0" + v.toString() : v.toString()
84✔
136
    }
137

138
    // Get date elements.
139
    const now = new Date()
14✔
140
    let year: any = now.getUTCFullYear().toString()
14✔
141
    let month: any = now.getUTCMonth() + 1
14✔
142
    let day: any = now.getUTCDate()
14✔
143
    let hour: any = now.getUTCHours()
14✔
144
    let minute: any = now.getUTCMinutes()
14✔
145
    let second: any = now.getUTCSeconds()
14✔
146

147
    return `${padLeft(year.substring(2))}-${padLeft(month)}-${padLeft(day)} ${padLeft(hour)}:${padLeft(minute)}:${padLeft(second)}`
14✔
148
}
149

150
/**
151
 * Check if the passed value is same as args.
152
 * @param value Object or value.
153
 */
154
export const isArguments = (value: any): boolean => {
3✔
155
    return isObject(value) && getTag(value) == "[object Arguments]"
3,355✔
156
}
157

158
/**
159
 * Check if the passed value is an array.
160
 * @param value Object or value.
161
 */
162
export const isArray = (value: any): boolean => {
3✔
163
    return value && Array.isArray(value)
144,427✔
164
}
165

166
/**
167
 * Check if the passed value is a date.
168
 * @param value Object or value.
169
 */
170
export const isDate = (value: any): boolean => {
3✔
171
    return value ? value instanceof Date : false
64,006!
172
}
173

174
/**
175
 * Check if the passed value is an error.
176
 * @param value Object or value.
177
 */
178
export const isError = (value: any): boolean => {
3✔
179
    if (!isObject(value)) {
3,232✔
180
        return false
3✔
181
    }
182

183
    const tag = getTag(value)
3,229✔
184
    return tag == "[object Error]" || tag == "[object DOMException]" || (typeof value.message === "string" && typeof value.name === "string" && !isPlainObject(value))
3,229✔
185
}
186

187
/**
188
 * Check if the passed value is a string.
189
 * @param value Object or value.
190
 */
191
export const isFunction = (value: any): boolean => {
3✔
192
    return typeof value === "function"
128,257✔
193
}
194

195
/**
196
 * Check if the passed value is null or undefined.
197
 * @param value Object or value.
198
 */
199
export const isNil = (value: any): boolean => {
3✔
200
    return value === null || typeof value == "undefined"
184✔
201
}
202

203
/**
204
 * Check if the passed value is an object.
205
 * @param value Object or value.
206
 */
207
export const isObject = (value: any): boolean => {
3✔
208
    return typeof value === "object" && value !== null
153,010✔
209
}
210

211
/**
212
 * Check if the passed value is a plain object.
213
 * @param value Object or value.
214
 */
215
export const isPlainObject = (value: any): boolean => {
3✔
216
    if (!isObject(value) || getTag(value) != "[object Object]") {
9✔
217
        return false
8✔
218
    }
219

220
    if (Object.getPrototypeOf(value) === null) {
1!
221
        return true
×
222
    }
223

224
    let proto = value
1✔
225
    while (Object.getPrototypeOf(proto) !== null) {
1✔
226
        proto = Object.getPrototypeOf(proto)
1✔
227
    }
228

229
    return Object.getPrototypeOf(value) === proto
1✔
230
}
231

232
/**
233
 * Check if the passed value is a string.
234
 * @param value Object or value.
235
 */
236
export const isString = (value): boolean => {
3✔
237
    const type = typeof value
2,325✔
238
    return type === "string" || (type === "object" && value != null && !Array.isArray(value) && getTag(value) == "[object String]")
2,325✔
239
}
240

241
/**
242
 * Merge the passed / immutable objects into one, and return the result.
243
 * @param obj The object to be cloned.
244
 */
245
export const mergeDeep = (...objects: any[]): any => {
3✔
246
    if (!objects) return objects
59!
247

248
    let mergeArrays = false
59✔
249

250
    if (objects[objects.length - 1] === true) {
59!
251
        mergeArrays = true
×
252
        objects.pop()
×
253
    }
254

255
    return objects.reduce((prev: any, obj: any) => {
59✔
256
        Object.keys(obj).forEach((key) => {
118✔
257
            const previous = prev[key]
609✔
258
            const current = obj[key]
609✔
259

260
            if (isArray(previous) && isArray(current)) {
609✔
261
                prev[key] = mergeArrays ? previous.concat(...current) : current
36!
262
            } else if (isObject(previous) && isObject(current)) {
573✔
263
                prev[key] = mergeDeep(previous, current)
10✔
264
            } else {
265
                prev[key] = current
563✔
266
            }
267
        })
268

269
        return prev
118✔
270
    }, {})
271
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc