caniemail
Version:
HTML and CSS Feature Support for Email Clients from caniemail.com
51 lines • 1.89 kB
JavaScript
import binarySearch from 'binary-search';
import splitLines from 'split-lines';
export class LocationIndex {
_lineStartEndTriples;
_stringLength;
constructor(source) {
// Ensure newline termination for consistency
if (source[source.length - 1] !== '\n') {
source += '\n';
}
this._stringLength = source.length;
this._lineStartEndTriples = [];
// Get lines with their endings preserved
const lines = splitLines(source, { preserveNewlines: true });
let currentPos = 0;
// Build index in a single pass through the pre-split lines
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const lineLength = lines[lineIndex].length;
this._lineStartEndTriples.push([lineIndex, currentPos, currentPos + lineLength]);
currentPos += lineLength;
}
}
locationOf(index) {
if (index < 0 || index >= this._stringLength) {
return null;
}
const foundIndex = binarySearch(this._lineStartEndTriples, index, (triple, needle) => {
if (needle < triple[1])
return 1;
if (needle >= triple[2])
return -1;
return 0;
});
// binarySearch returns negative when not found
if (foundIndex < 0)
return null;
const triple = this._lineStartEndTriples[foundIndex];
return {
line: triple[0] + 1, // Convert to 1-based line numbers
column: index - triple[1] + 1 // Convert to 1-based column numbers
};
}
positionOf(startIndex, endIndex) {
const start = this.locationOf(startIndex);
const end = this.locationOf(endIndex);
if (!start || !end)
return undefined;
return { start, end };
}
}
//# sourceMappingURL=location.js.map