stoplightio/yaml

View on GitHub
src/lineForPosition.ts

Summary

Maintainability
A
1 hr
Test Coverage
A
100%
/**
 * A performant way to find the appropriate line for the given position.
 *
 * This is key to making the yaml line mapping performant.
 */
export const lineForPosition = (pos: number, lines: number[], start: number = 0, end?: number): number => {
  // position 0 is always line 0
  if (pos === 0 || lines.length === 0 || pos < lines[0]) {
    return 0;
  }

  // start with max range, 0 - lines.length
  if (typeof end === 'undefined') {
    end = lines.length;
  }

  // target should be the halfway point between start and end
  const target = Math.floor((end - start) / 2) + start;
  if (pos >= lines[target] && !lines[target + 1]) {
    return target + 1;
  }

  // if pos is between target and the next line's position, we're good!
  const nextLinePos = lines[Math.min(target + 1, lines.length)];

  if (pos === lines[target] - 1) {
    return target;
  }

  if (pos >= lines[target] && pos <= nextLinePos) {
    if (pos === nextLinePos) {
      return target + 2;
    }

    return target + 1;
  }

  // if pos is above the current line position, then we need to go "up"
  if (pos > lines[target]) {
    return lineForPosition(pos, lines, target + 1, end);
  } else {
    // else we take the bottom half
    return lineForPosition(pos, lines, start, target - 1);
  }
};