line-mappings.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright Google LLC All Rights Reserved.
  5. *
  6. * Use of this source code is governed by an MIT-style license that can be
  7. * found in the LICENSE file at https://angular.dev/license
  8. */
  9. Object.defineProperty(exports, "__esModule", { value: true });
  10. exports.getLineAndCharacterFromPosition = getLineAndCharacterFromPosition;
  11. exports.computeLineStartsMap = computeLineStartsMap;
  12. /*
  13. * Line mapping utilities which can be used to retrieve line and character based
  14. * on an absolute character position in a given file. This functionality is similar
  15. * to TypeScript's "ts.getLineAndCharacterFromPosition" utility, but we cannot leverage
  16. * their logic for line mappings as it's internal and we need to generate line mappings
  17. * for non-TypeScript files such as HTML templates or stylesheets.
  18. *
  19. * Line and character can be retrieved by splitting a given source text based on
  20. * line breaks into line start entries. Later when a specific position is requested,
  21. * the closest line-start position is determined based on the given position.
  22. */
  23. const LF_CHAR = 10;
  24. const CR_CHAR = 13;
  25. const LINE_SEP_CHAR = 8232;
  26. const PARAGRAPH_CHAR = 8233;
  27. /** Gets the line and character for the given position from the line starts map. */
  28. function getLineAndCharacterFromPosition(lineStartsMap, position) {
  29. const lineIndex = findClosestLineStartPosition(lineStartsMap, position);
  30. return { character: position - lineStartsMap[lineIndex], line: lineIndex };
  31. }
  32. /**
  33. * Computes the line start map of the given text. This can be used in order to
  34. * retrieve the line and character of a given text position index.
  35. */
  36. function computeLineStartsMap(text) {
  37. const result = [0];
  38. let pos = 0;
  39. while (pos < text.length) {
  40. const char = text.charCodeAt(pos++);
  41. // Handles the "CRLF" line break. In that case we peek the character
  42. // after the "CR" and check if it is a line feed.
  43. if (char === CR_CHAR) {
  44. if (text.charCodeAt(pos) === LF_CHAR) {
  45. pos++;
  46. }
  47. result.push(pos);
  48. }
  49. else if (char === LF_CHAR || char === LINE_SEP_CHAR || char === PARAGRAPH_CHAR) {
  50. result.push(pos);
  51. }
  52. }
  53. result.push(pos);
  54. return result;
  55. }
  56. /** Finds the closest line start for the given position. */
  57. function findClosestLineStartPosition(linesMap, position, low = 0, high = linesMap.length - 1) {
  58. while (low <= high) {
  59. const pivotIndex = Math.floor((low + high) / 2);
  60. const pivotEl = linesMap[pivotIndex];
  61. if (pivotEl === position) {
  62. return pivotIndex;
  63. }
  64. else if (position > pivotEl) {
  65. low = pivotIndex + 1;
  66. }
  67. else {
  68. high = pivotIndex - 1;
  69. }
  70. }
  71. // In case there was no exact match, return the closest "lower" line index. We also
  72. // subtract the index by one because want the index of the previous line start.
  73. return low - 1;
  74. }
  75. //# sourceMappingURL=line-mappings.js.map