You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
2.7 KiB

/**
* @author Titus Wormer
* @copyright 2016 Titus Wormer
* @license MIT
* @module vfile-location
* @fileoverview Convert between positions (line and column-based)
* and offsets (range-based) locations in a virtual file.
*/
'use strict';
/* Expose. */
module.exports = factory;
/**
* Factory.
*
* @param {VFile|string|Buffer} file - Virtual file or document.
*/
function factory(file) {
var contents = indices(String(file));
return {
toPosition: offsetToPositionFactory(contents),
toOffset: positionToOffsetFactory(contents)
};
}
/**
* Factory to get the line and column-based `position` for
* `offset` in the bound indices.
*
* @param {Array.<number>} indices - Indices of
* line-breaks in `value`.
* @return {Function} - Bound method.
*/
function offsetToPositionFactory(indices) {
return offsetToPosition;
/**
* Get the line and column-based `position` for
* `offset` in the bound indices.
*
* @param {number} offset - Offset.
* @return {Position} - Object with `line`, `column`,
* and `offset` properties based on the bound
* `indices`. An empty object when given invalid
* or out of bounds input.
*/
function offsetToPosition(offset) {
var index = -1;
var length = indices.length;
if (offset < 0) {
return {};
}
while (++index < length) {
if (indices[index] > offset) {
return {
line: index + 1,
column: (offset - (indices[index - 1] || 0)) + 1,
offset: offset
};
}
}
return {};
}
}
/**
* Factory to get the `offset` for a line and column-based
* `position` in the bound indices.
*
* @param {Array.<number>} indices - Indices of
* line-breaks in `value`.
* @return {Function} - Bound method.
*/
function positionToOffsetFactory(indices) {
return positionToOffset;
/**
* Get the `offset` for a line and column-based
* `position` in the bound indices.
*
* @param {Position} position - Object with `line` and
* `column` properties.
* @return {number} - Offset. `-1` when given invalid
* or out of bounds input.
*/
function positionToOffset(position) {
var line = position && position.line;
var column = position && position.column;
if (!isNaN(line) && !isNaN(column) && line - 1 in indices) {
return ((indices[line - 2] || 0) + column - 1) || 0;
}
return -1;
}
}
/**
* Get indices of line-breaks in `value`.
*
* @param {string} value - Value.
* @return {Array.<number>} - List of indices of
* line-breaks.
*/
function indices(value) {
var result = [];
var index = value.indexOf('\n');
while (index !== -1) {
result.push(index + 1);
index = value.indexOf('\n', index + 1);
}
result.push(value.length + 1);
return result;
}