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