df3e26f3850d2049e9d800bbfeb5c6bc976dea7b509fced65b616b28b0aa4973d33a1d214d63b5da6a15f90c9cfa45fd0e0ae40add0dd8ba92e3b6aa359100 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import Op from './Op';
  2. export default class Iterator {
  3. ops: Op[];
  4. index: number;
  5. offset: number;
  6. constructor(ops: Op[]) {
  7. this.ops = ops;
  8. this.index = 0;
  9. this.offset = 0;
  10. }
  11. hasNext(): boolean {
  12. return this.peekLength() < Infinity;
  13. }
  14. next(length?: number): Op {
  15. if (!length) {
  16. length = Infinity;
  17. }
  18. const nextOp = this.ops[this.index];
  19. if (nextOp) {
  20. const offset = this.offset;
  21. const opLength = Op.length(nextOp);
  22. if (length >= opLength - offset) {
  23. length = opLength - offset;
  24. this.index += 1;
  25. this.offset = 0;
  26. } else {
  27. this.offset += length;
  28. }
  29. if (typeof nextOp.delete === 'number') {
  30. return { delete: length };
  31. } else {
  32. const retOp: Op = {};
  33. if (nextOp.attributes) {
  34. retOp.attributes = nextOp.attributes;
  35. }
  36. if (typeof nextOp.retain === 'number') {
  37. retOp.retain = length;
  38. } else if (
  39. typeof nextOp.retain === 'object' &&
  40. nextOp.retain !== null
  41. ) {
  42. // offset should === 0, length should === 1
  43. retOp.retain = nextOp.retain;
  44. } else if (typeof nextOp.insert === 'string') {
  45. retOp.insert = nextOp.insert.substr(offset, length);
  46. } else {
  47. // offset should === 0, length should === 1
  48. retOp.insert = nextOp.insert;
  49. }
  50. return retOp;
  51. }
  52. } else {
  53. return { retain: Infinity };
  54. }
  55. }
  56. peek(): Op {
  57. return this.ops[this.index];
  58. }
  59. peekLength(): number {
  60. if (this.ops[this.index]) {
  61. // Should never return 0 if our index is being managed correctly
  62. return Op.length(this.ops[this.index]) - this.offset;
  63. } else {
  64. return Infinity;
  65. }
  66. }
  67. peekType(): string {
  68. const op = this.ops[this.index];
  69. if (op) {
  70. if (typeof op.delete === 'number') {
  71. return 'delete';
  72. } else if (
  73. typeof op.retain === 'number' ||
  74. (typeof op.retain === 'object' && op.retain !== null)
  75. ) {
  76. return 'retain';
  77. } else {
  78. return 'insert';
  79. }
  80. }
  81. return 'retain';
  82. }
  83. rest(): Op[] {
  84. if (!this.hasNext()) {
  85. return [];
  86. } else if (this.offset === 0) {
  87. return this.ops.slice(this.index);
  88. } else {
  89. const offset = this.offset;
  90. const index = this.index;
  91. const next = this.next();
  92. const rest = this.ops.slice(this.index);
  93. this.offset = offset;
  94. this.index = index;
  95. return [next].concat(rest);
  96. }
  97. }
  98. }