line-counter.js 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. 'use strict';
  2. /**
  3. * Tracks newlines during parsing in order to provide an efficient API for
  4. * determining the one-indexed `{ line, col }` position for any offset
  5. * within the input.
  6. */
  7. class LineCounter {
  8. constructor() {
  9. this.lineStarts = [];
  10. /**
  11. * Should be called in ascending order. Otherwise, call
  12. * `lineCounter.lineStarts.sort()` before calling `linePos()`.
  13. */
  14. this.addNewLine = (offset) => this.lineStarts.push(offset);
  15. /**
  16. * Performs a binary search and returns the 1-indexed { line, col }
  17. * position of `offset`. If `line === 0`, `addNewLine` has never been
  18. * called or `offset` is before the first known newline.
  19. */
  20. this.linePos = (offset) => {
  21. let low = 0;
  22. let high = this.lineStarts.length;
  23. while (low < high) {
  24. const mid = (low + high) >> 1; // Math.floor((low + high) / 2)
  25. if (this.lineStarts[mid] < offset)
  26. low = mid + 1;
  27. else
  28. high = mid;
  29. }
  30. if (this.lineStarts[low] === offset)
  31. return { line: low + 1, col: 1 };
  32. if (low === 0)
  33. return { line: 0, col: offset };
  34. const start = this.lineStarts[low - 1];
  35. return { line: low, col: offset - start + 1 };
  36. };
  37. }
  38. }
  39. exports.LineCounter = LineCounter;