src/optic_array.js

  1. import { isEmpty, isUndefined, reduce, reduceRight } from 'underscore';
  2. import Optic from './optic.js';
  3. import { isLens, lensCap } from './utils.js';
  4. /**
  5. * @extends Optic
  6. */
  7. class OpticArray extends Optic {
  8. /**
  9. * @summary Aggregation of multiple lens applied in series
  10. *
  11. * @description
  12. * Construct this using {@link module:natural-lenses#fuse}.
  13. */
  14. constructor(lenses) {
  15. super();
  16. this.lenses = lenses;
  17. }
  18. /**
  19. * @inheritdoc
  20. */
  21. present(subject) {
  22. if (this.lenses.length === 0) return true;
  23. const throughLenses = this.lenses.slice(), finalLens = throughLenses.pop();
  24. const rval = reduce(
  25. throughLenses,
  26. (subject, lens) => lens.get(subject),
  27. subject
  28. );
  29. return finalLens.present(rval);
  30. }
  31. /**
  32. * @inheritdoc
  33. */
  34. get(subject, ...tail) {
  35. const subjResult = reduce(
  36. this.lenses,
  37. (subject, lens) => lens.get(subject),
  38. subject
  39. );
  40. if (tail.length > 0) {
  41. return isLens(subjResult) ? subjResult.get(...tail) : undefined
  42. }
  43. return subjResult;
  44. }
  45. /**
  46. * @inheritdoc
  47. */
  48. get_maybe(subject, ...tail) {
  49. const stepSubject = get_maybe_internal.call(this, {just: subject});
  50. const subjResult = stepSubject.just;
  51. if (tail.length > 0) {
  52. return isLens(subjResult) ? subjResult.get_maybe(...tail) : {};
  53. }
  54. return stepSubject;
  55. }
  56. /**
  57. * @inheritdoc
  58. */
  59. xformInClone_maybe(subject, fn) {
  60. var i;
  61. const lensSubjects = new Array(this.lenses.length);
  62. lensSubjects[0] = {just: subject};
  63. const leadingLensCount = this.lenses.length - 1;
  64. for (i = 0; i < leadingLensCount; i++) {
  65. const l = this.lenses[i];
  66. lensSubjects[i + 1] = l.get_maybe(lensSubjects[i].just);
  67. if (!('just' in lensSubjects[i + 1])) {
  68. break;
  69. }
  70. }
  71. const xformResults = new Array(this.lenses.length);
  72. i = this.lenses.length - 1;
  73. const xformInput_maybe = (lensSubjects[i] || {});
  74. xformResults[i] = this.lenses[i].xformInClone_maybe(xformInput_maybe.just, fn);
  75. if ('just' in xformInput_maybe) {
  76. if (xformResults[i] === xformInput_maybe.just) {
  77. return subject;
  78. }
  79. }
  80. for (i = leadingLensCount - 1; i >= 0; i--) {
  81. let lensSubject = lensSubjects[i] || {};
  82. xformResults[i] = this.lenses[i].setInClone(lensSubject.just, xformResults[i + 1]);
  83. }
  84. return xformResults[0];
  85. }
  86. }
  87. export default OpticArray;
  88. /**
  89. * @private
  90. * @this OpticArray
  91. * @param {Maybe.<*>} subject_maybe
  92. * @returns {Maybe.<*>}
  93. */
  94. function get_maybe_internal(subject_maybe) {
  95. let stepSubject = subject_maybe;
  96. for (let i = 0; i < this.lenses.length; i++) {
  97. const lens = this.lenses[i];
  98. stepSubject = lens.get_maybe(stepSubject.just);
  99. if (isEmpty(stepSubject.just)) {
  100. return {};
  101. }
  102. }
  103. return stepSubject;
  104. }