1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.isLineBreak = void 0;
|
4 | function isLineBreak(ch) {
|
5 | // ES5 7.3:
|
6 | // The ECMAScript line terminator characters are listed in Table 3.
|
7 | // Table 3: Line Terminator Characters
|
8 | // Code Unit Value Name Formal Name
|
9 | // \u000A Line Feed <LF>
|
10 | // \u000D Carriage Return <CR>
|
11 | // \u2028 Line separator <LS>
|
12 | // \u2029 Paragraph separator <PS>
|
13 | // Only the characters in Table 3 are treated as line terminators. Other new line or line
|
14 | // breaking characters are treated as white space but not as line terminators.
|
15 | return (ch === 10 /* LineFeed */ ||
|
16 | ch === 13 /* CarriageReturn */ ||
|
17 | ch === 8232 /* LineSeparator */ ||
|
18 | ch === 8233 /* ParagraphSeparator */);
|
19 | }
|
20 | exports.isLineBreak = isLineBreak;
|
21 | class SourceFile {
|
22 | constructor(file) {
|
23 | this.file = file;
|
24 | this.lineStarts = this.computeLineStarts();
|
25 | }
|
26 | get name() {
|
27 | return this.file.name;
|
28 | }
|
29 | get content() {
|
30 | return this.file.textContent;
|
31 | }
|
32 | getLocation(range) {
|
33 | return {
|
34 | end: this.getPosition(range[1]),
|
35 | start: this.getPosition(range[0]),
|
36 | };
|
37 | }
|
38 | getPosition(pos) {
|
39 | let lineNumber = this.binarySearch(pos);
|
40 | if (lineNumber < 0) {
|
41 | // If the actual position was not found,
|
42 | // the binary search returns the 2's-complement of the next line start
|
43 | // e.g. if the line starts at [5, 10, 23, 80] and the position requested was 20
|
44 | // then the search will return -2.
|
45 | //
|
46 | // We want the index of the previous line start, so we subtract 1.
|
47 | // Review 2's-complement if this is confusing.
|
48 | lineNumber = ~lineNumber - 1;
|
49 | }
|
50 | return {
|
51 | column: pos - this.lineStarts[lineNumber],
|
52 | line: lineNumber,
|
53 | };
|
54 | }
|
55 | /**
|
56 | * Performs a binary search, finding the index at which 'value' occurs in 'array'.
|
57 | * If no such index is found, returns the 2's-complement of first index at which
|
58 | * number[index] exceeds number.
|
59 | * @param array A sorted array whose first element must be no larger than number
|
60 | * @param number The value to be searched for in the array.
|
61 | */
|
62 | binarySearch(position, offset = 0) {
|
63 | let low = offset;
|
64 | let high = this.lineStarts.length - 1;
|
65 | while (low <= high) {
|
66 | const middle = low + ((high - low) >> 1);
|
67 | const midValue = this.lineStarts[middle];
|
68 | if (midValue === position) {
|
69 | return middle;
|
70 | }
|
71 | else if (midValue > position) {
|
72 | high = middle - 1;
|
73 | }
|
74 | else {
|
75 | low = middle + 1;
|
76 | }
|
77 | }
|
78 | return ~low;
|
79 | }
|
80 | computeLineStarts() {
|
81 | const result = [];
|
82 | let pos = 0;
|
83 | let lineStart = 0;
|
84 | const markLineStart = () => {
|
85 | result.push(lineStart);
|
86 | lineStart = pos;
|
87 | };
|
88 | while (pos < this.file.textContent.length) {
|
89 | const ch = this.file.textContent.charCodeAt(pos);
|
90 | pos++;
|
91 | switch (ch) {
|
92 | case 13 /* CarriageReturn */:
|
93 | if (this.file.textContent.charCodeAt(pos) === 10 /* LineFeed */) {
|
94 | pos++;
|
95 | }
|
96 | markLineStart();
|
97 | break;
|
98 | case 10 /* LineFeed */:
|
99 | markLineStart();
|
100 | break;
|
101 | default:
|
102 | if (ch > 127 /* MaxAsciiCharacter */ && isLineBreak(ch)) {
|
103 | markLineStart();
|
104 | }
|
105 | break;
|
106 | }
|
107 | }
|
108 | result.push(lineStart);
|
109 | return result;
|
110 | }
|
111 | }
|
112 | exports.default = SourceFile;
|
113 | //# sourceMappingURL=SourceFile.js.map |
\ | No newline at end of file |