deep-map.js 2.1 KB

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