createFrameGroups.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { State, Frame, FrameGroup } from '../types';
  2. import { getFrameType } from '../helpers';
  3. type IterationContext = {
  4. current: Frame;
  5. previous: FrameGroup;
  6. isFirstFrame: boolean;
  7. frameNumber: number;
  8. expanded: Array<number>;
  9. selected: number;
  10. };
  11. const dummyFrameGroup: FrameGroup = {
  12. type: 'application',
  13. relative_file: '',
  14. expanded: true,
  15. frames: [],
  16. };
  17. export default function createFrameGroups({
  18. frames,
  19. selected,
  20. expanded,
  21. }: State): Array<FrameGroup> {
  22. return frames.reduce(
  23. (frameGroups, current, i) => {
  24. const context: IterationContext = {
  25. current,
  26. previous: frameGroups[frameGroups.length - 1] || dummyFrameGroup,
  27. isFirstFrame: i === 0,
  28. frameNumber: frames.length - i,
  29. expanded,
  30. selected,
  31. };
  32. if (context.expanded.includes(context.frameNumber)) {
  33. return frameGroups.concat(parseExpandedFrame(context));
  34. }
  35. return frameGroups.concat(parseCollapsedFrame(context));
  36. },
  37. [] as Array<FrameGroup>,
  38. );
  39. }
  40. function parseExpandedFrame(context: IterationContext): Array<FrameGroup> {
  41. if (context.current.relative_file !== context.previous.relative_file) {
  42. return [
  43. {
  44. type: getFrameType(context.current),
  45. relative_file: context.current.relative_file,
  46. expanded: true,
  47. frames: [
  48. {
  49. ...context.current,
  50. frame_number: context.frameNumber,
  51. selected: context.selected === context.frameNumber,
  52. },
  53. ],
  54. },
  55. ];
  56. }
  57. context.previous.frames.push({
  58. ...context.current,
  59. frame_number: context.frameNumber,
  60. selected: context.selected === context.frameNumber,
  61. });
  62. return [];
  63. }
  64. function parseCollapsedFrame(context: IterationContext): Array<FrameGroup> {
  65. const type = getFrameType(context.current);
  66. if (
  67. (!context.previous.expanded && type === context.previous.type) ||
  68. context.previous.relative_file === context.current.relative_file
  69. ) {
  70. // Mutate the previous result. It's not pretty, makes the general flow of the program less
  71. // complex because we kan keep the result list append-only.
  72. context.previous.frames.push({
  73. ...context.current,
  74. selected: false,
  75. frame_number: context.frameNumber,
  76. });
  77. return [];
  78. }
  79. return [
  80. {
  81. type,
  82. relative_file: context.current.relative_file,
  83. expanded: false,
  84. frames: [
  85. {
  86. ...context.current,
  87. frame_number: context.frameNumber,
  88. selected: context.selected === context.frameNumber,
  89. },
  90. ],
  91. },
  92. ];
  93. }