|
| 1 | +function filterError (input) { |
| 2 | + return { |
| 3 | + errorType: input.name, |
| 4 | + message: input.message, |
| 5 | + stack: input.stack, |
| 6 | + ...(input.code ? { code: input.code } : {}), |
| 7 | + ...(input.statusCode ? { statusCode: input.statusCode } : {}), |
| 8 | + } |
| 9 | +} |
| 10 | + |
| 11 | +const deepMap = (input, handler = v => v, path = ['$'], seen = new Set([input])) => { |
| 12 | + // this is in an effort to maintain bole's error logging behavior |
| 13 | + if (path.join('.') === '$' && input instanceof Error) { |
| 14 | + return deepMap({ err: filterError(input) }, handler, path, seen) |
| 15 | + } |
| 16 | + if (input instanceof Error) { |
| 17 | + return deepMap(filterError(input), handler, path, seen) |
| 18 | + } |
| 19 | + if (input instanceof Buffer) { |
| 20 | + return `[unable to log instanceof buffer]` |
| 21 | + } |
| 22 | + if (input instanceof Uint8Array) { |
| 23 | + return `[unable to log instanceof Uint8Array]` |
| 24 | + } |
| 25 | + |
| 26 | + if (Array.isArray(input)) { |
| 27 | + const result = [] |
| 28 | + for (let i = 0; i < input.length; i++) { |
| 29 | + const element = input[i] |
| 30 | + const elementPath = [...path, i] |
| 31 | + if (element instanceof Object) { |
| 32 | + if (!seen.has(element)) { // avoid getting stuck in circular reference |
| 33 | + seen.add(element) |
| 34 | + result.push(deepMap(handler(element, elementPath), handler, elementPath, seen)) |
| 35 | + } |
| 36 | + } else { |
| 37 | + result.push(handler(element, elementPath)) |
| 38 | + } |
| 39 | + } |
| 40 | + return result |
| 41 | + } |
| 42 | + |
| 43 | + if (input === null) { |
| 44 | + return null |
| 45 | + } else if (typeof input === 'object' || typeof input === 'function') { |
| 46 | + const result = {} |
| 47 | + |
| 48 | + for (const propertyName of Object.getOwnPropertyNames(input)) { |
| 49 | + // skip logging internal properties |
| 50 | + if (propertyName.startsWith('_')) { |
| 51 | + continue |
| 52 | + } |
| 53 | + |
| 54 | + try { |
| 55 | + const property = input[propertyName] |
| 56 | + const propertyPath = [...path, propertyName] |
| 57 | + if (property instanceof Object) { |
| 58 | + if (!seen.has(property)) { // avoid getting stuck in circular reference |
| 59 | + seen.add(property) |
| 60 | + result[propertyName] = deepMap( |
| 61 | + handler(property, propertyPath), handler, propertyPath, seen |
| 62 | + ) |
| 63 | + } |
| 64 | + } else { |
| 65 | + result[propertyName] = handler(property, propertyPath) |
| 66 | + } |
| 67 | + } catch (err) { |
| 68 | + // a getter may throw an error |
| 69 | + result[propertyName] = `[error getting value: ${err.message}]` |
| 70 | + } |
| 71 | + } |
| 72 | + return result |
| 73 | + } |
| 74 | + |
| 75 | + return handler(input, path) |
| 76 | +} |
| 77 | + |
| 78 | +module.exports = { deepMap } |
0 commit comments