deep-map.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  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. // allows for non-node js environments, sush as workers
  11. if (typeof Buffer !== 'undefined' && input instanceof Buffer) {
  12. return `[unable to log instanceof buffer]`
  13. }
  14. if (input instanceof Uint8Array) {
  15. return `[unable to log instanceof Uint8Array]`
  16. }
  17. if (Array.isArray(input)) {
  18. const result = []
  19. for (let i = 0; i < input.length; i++) {
  20. const element = input[i]
  21. const elementPath = [...path, i]
  22. if (element instanceof Object) {
  23. if (!seen.has(element)) { // avoid getting stuck in circular reference
  24. seen.add(element)
  25. result.push(deepMap(handler(element, elementPath), handler, elementPath, seen))
  26. }
  27. } else {
  28. result.push(handler(element, elementPath))
  29. }
  30. }
  31. return result
  32. }
  33. if (input === null) {
  34. return null
  35. } else if (typeof input === 'object' || typeof input === 'function') {
  36. const result = {}
  37. for (const propertyName of Object.getOwnPropertyNames(input)) {
  38. // skip logging internal properties
  39. if (propertyName.startsWith('_')) {
  40. continue
  41. }
  42. try {
  43. const property = input[propertyName]
  44. const propertyPath = [...path, propertyName]
  45. if (property instanceof Object) {
  46. if (!seen.has(property)) { // avoid getting stuck in circular reference
  47. seen.add(property)
  48. result[propertyName] = deepMap(
  49. handler(property, propertyPath), handler, propertyPath, seen
  50. )
  51. }
  52. } else {
  53. result[propertyName] = handler(property, propertyPath)
  54. }
  55. } catch (err) {
  56. // a getter may throw an error
  57. result[propertyName] = `[error getting value: ${err.message}]`
  58. }
  59. }
  60. return result
  61. }
  62. return handler(input, path)
  63. }
  64. module.exports = { deepMap }