objectUtils.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /**
  2. * @category Services/utils
  3. * Utilitaire aidant à manipuler des Objets
  4. */
  5. import _ from 'lodash'
  6. import type { AnyJson } from '~/types/data'
  7. import StringUtils from '~/services/utils/stringUtils'
  8. const ObjectUtils = {
  9. /**
  10. * Flatten un objet nested en un objet avec un seul niveau avec des noms de propriétés transformées comme cela 'foo.bar'
  11. * L'objet passé en paramètre reste inchangé car il est cloné
  12. *
  13. * @example cloneAndFlatten({ a: 1, b: { c: 2 }, d: { e: 3, f: { g: 4, h: 5 } }, i: { j: 6 } }, ['i']) => { a: 1, 'b.c': 2, 'd.e': 3, 'd.f.g': 4, 'd.f.h': 5, i: { j: 6 } } }
  14. * @param {AnyJson} object
  15. * @param {Array<string>} excludedProperties
  16. * @param excludedProperties
  17. * @return {AnyJson}
  18. */
  19. cloneAndFlatten(
  20. object: AnyJson,
  21. excludedProperties: Array<string> = [],
  22. ): AnyJson {
  23. if (typeof object !== 'object') {
  24. throw new TypeError('Expecting an object parameter')
  25. }
  26. return Object.keys(object).reduce((values: AnyJson, name: string) => {
  27. if (!Object.prototype.hasOwnProperty.call(object, name)) {
  28. return values
  29. }
  30. if (this.isObject(object[name])) {
  31. if (!excludedProperties.includes(name)) {
  32. const flatObject = this.cloneAndFlatten(object[name])
  33. Object.keys(flatObject).forEach((flatObjectKey) => {
  34. if (
  35. !Object.prototype.hasOwnProperty.call(flatObject, flatObjectKey)
  36. ) {
  37. return
  38. }
  39. values[name + '.' + flatObjectKey] = flatObject[flatObjectKey]
  40. })
  41. } else {
  42. values[name] = this.clone(object[name])
  43. }
  44. } else {
  45. values[name] = object[name]
  46. }
  47. return values
  48. }, {})
  49. },
  50. /**
  51. * Transforme un objet flattened en un objet nested. L'objet passé en paramètre reste inchangé
  52. *
  53. * @example cloneAndNest({ a: 1, 'b.c': 2, 'd.e': 3, 'd.f.g': 4, 'd.f.h': 5 } ) => { a: 1, b: { c: 2 }, d: { e: 3, f: { g: 4, h: 5 } } }
  54. * @param {AnyJson} object
  55. * @return {AnyJson}
  56. */
  57. cloneAndNest(object: AnyJson): AnyJson {
  58. if (typeof object !== 'object') {
  59. throw new TypeError('Expecting an object parameter')
  60. }
  61. return Object.keys(object).reduce((values, name) => {
  62. if (!Object.prototype.hasOwnProperty.call(object, name)) {
  63. return values
  64. }
  65. name
  66. .split('.')
  67. .reduce(
  68. (
  69. previous: AnyJson,
  70. current: string,
  71. index: number,
  72. list: Array<string>,
  73. ) => {
  74. if (previous != null) {
  75. if (typeof previous[current] === 'undefined') {
  76. previous[current] = {}
  77. }
  78. if (index < list.length - 1) {
  79. return previous[current]
  80. }
  81. previous[current] = object[name]
  82. }
  83. return null
  84. },
  85. values,
  86. )
  87. return values
  88. }, {})
  89. },
  90. /**
  91. * Teste si le paramètre est un objet
  92. *
  93. * @param {AnyJson} value
  94. * @return {boolean}
  95. */
  96. isObject(value: unknown): boolean {
  97. return (
  98. value !== null &&
  99. typeof value === 'object' &&
  100. !Array.isArray(value) &&
  101. Object.prototype.toString.call(value) !== '[object Date]'
  102. )
  103. },
  104. /**
  105. * Clone l'objet et ses propriétés.
  106. *
  107. * @param {ObjectUtils} object
  108. * @return {ObjectUtils}
  109. */
  110. clone(object: AnyJson): AnyJson {
  111. return Object.keys(object).reduce((values: AnyJson, name: string) => {
  112. if (Object.prototype.hasOwnProperty.call(object, name)) {
  113. values[name] = object[name]
  114. }
  115. return values
  116. }, {})
  117. },
  118. /**
  119. * Trie un objet selon ses clés (par ordre alphanumérique)
  120. *
  121. * @example sortObjectsByKey({b:1, d:2, c:3, a:4}) => {a:4, b:1, c:3, d:2}
  122. * @param toSort
  123. */
  124. sortObjectsByKey(toSort: AnyJson): AnyJson {
  125. if (typeof toSort !== 'object') {
  126. throw new TypeError('Expecting an object parameter')
  127. }
  128. return Object.keys(toSort)
  129. .sort()
  130. .reduce((obj: AnyJson, key: string) => {
  131. obj[key] = toSort[key]
  132. return obj
  133. }, {})
  134. },
  135. /**
  136. * Créé un hash à partir d'un objet
  137. * (après l'avoir trié selon ses clés, et converti en json sans espace)
  138. *
  139. * @param obj
  140. */
  141. async hash(obj: object): Promise<string> {
  142. const sortedObject = this.sortObjectsByKey(_.cloneDeep(obj))
  143. return await StringUtils.hash(JSON.stringify(sortedObject), 'SHA-1')
  144. }
  145. }
  146. export default ObjectUtils