util/UsingWrapper.js

  1. import * as array from 'array'
  2. import * as collection from 'collection'
  3. import * as lang from 'lang'
  4. import * as math from 'math'
  5. import * as object from 'object'
  6. import * as string from 'string'
  7. import concat from 'lodash/concat'
  8. import drop from 'lodash/drop'
  9. import get from 'lodash/get'
  10. import head from 'lodash/head'
  11. import isSymbol from 'lodash/isSymbol'
  12. import map from 'lodash/map'
  13. import mapValues from 'lodash/mapValues'
  14. import omit from 'lodash/omit'
  15. /**
  16. * Wrapper allowing to specify one or several paths to use as arguments for an immutadot function call.<br/>
  17. * Instances are created by calling {@link object.using}.
  18. * @memberof util
  19. * @see {@link object.using} for more information.
  20. * @private
  21. * @since 0.1.12
  22. */
  23. class UsingWrapper {
  24. /**
  25. * This constructor should not be called directly.<br/>
  26. * Instances are created by calling {@link object.using}.
  27. * @param {...(Array|string)} paths The paths to use as arguments.
  28. * @see {@link object.using} for more information.
  29. * @since 0.1.12
  30. */
  31. constructor(...paths) {
  32. this._paths = paths
  33. }
  34. /**
  35. * Argument placeholder.
  36. * @since 0.2.1
  37. */
  38. static placeholder = Symbol.for('immutadot.using.placeholder')
  39. /**
  40. * Call a function with the specified arguments and possibly some more arguments.
  41. * @param {function} fn The function to call.
  42. * @param {Object} object The object to modify.
  43. * @param {Array|string} path The path of the property to be set.
  44. * @param {Array} pArgs The arguments for the function call.
  45. * @return {Object} Returns the updated object.
  46. * @since 0.1.12
  47. */
  48. _call(fn, object, path, pArgs) {
  49. let callArgs = pArgs
  50. const args = concat(
  51. map(this._paths, usingPath => {
  52. if (isSymbol(usingPath)) {
  53. const arg = head(callArgs)
  54. callArgs = drop(callArgs)
  55. return arg
  56. }
  57. return get(object, usingPath)
  58. }),
  59. callArgs,
  60. )
  61. return fn(object, path, ...args)
  62. }
  63. }
  64. // Add namespaces functions to the UsingWrapper prototype
  65. [
  66. array,
  67. collection,
  68. { ...omit(object, ['unset']) },
  69. lang,
  70. math,
  71. object,
  72. string,
  73. ].forEach(namespace => Object.assign(
  74. UsingWrapper.prototype,
  75. mapValues(
  76. namespace,
  77. fn => function(object, path, ...args) {
  78. return this._call(fn, object, path, args) // eslint-disable-line no-invalid-this
  79. },
  80. ),
  81. ))
  82. export { UsingWrapper, UsingWrapper as default }