Commit cbd77960 authored by David Sveningsson's avatar David Sveningsson
Browse files

feat(location): allow sliceLocation to wrap line/column

parent d718405d
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -68,4 +68,23 @@ describe("sliceLocation()", () => {
			size: null,
		});
	});

	it("should wrap line/column when newlines are present", () => {
		const text = "foo\nbar baz\nspam";
		(location as any).size = text.length;
		expect(sliceLocation(location, 8, 11, text)).toEqual({
			filename: "-",
			offset: 8,
			line: 2,
			column: 5,
			size: 3,
		});
		expect(sliceLocation(location, 12, 16, text)).toEqual({
			filename: "-",
			offset: 12,
			line: 3,
			column: 1,
			size: 4,
		});
	});
});
+33 −4
Original line number Diff line number Diff line
@@ -27,6 +27,14 @@ export interface Location {
	readonly size?: number;
}

interface LocationRW {
	filename: string;
	offset: number;
	line: number;
	column: number;
	size?: number;
}

function sliceSize(size: number, begin: number, end?: number): number {
	if (typeof size !== "number") {
		return size;
@@ -43,26 +51,47 @@ function sliceSize(size: number, begin: number, end?: number): number {
/**
 * Calculate a new location by offsetting this location.
 *
 * It is assumed there is no newlines anywhere between current location and
 * the new.
 * If the references text with newlines the wrap parameter must be set to
 * properly calculate line and column information. If not given the text is
 * assumed to contain no newlines.
 *
 * @param location Source location
 * @param begin - Start location. Default is 0.
 * @param end - End location. Default is size of location. Negative values are
 * counted from end, e.g. `-2` means `size - 2`.
 * @param wrap - If given, line/column is wrapped for each newline occuring
 * before location end.
 */
export function sliceLocation(
	location: Location,
	begin: number,
	end?: number
	end?: number,
	wrap?: string
): Location {
	if (!location) return null;
	const size = sliceSize(location.size, begin, end);
	return {
	const sliced: LocationRW = {
		filename: location.filename,
		offset: location.offset + begin,
		line: location.line,
		column: location.column + begin,
		size,
	};

	/* if text content is provided try to find all newlines and modify line/column accordingly */
	if (wrap) {
		let index = -1;
		const col = sliced.column;
		do {
			index = wrap.indexOf("\n", index + 1);
			if (index >= 0 && index < begin) {
				sliced.column = col - (index + 1);
				sliced.line++;
			} else {
				break;
			}
		} while (true); // eslint-disable-line no-constant-condition
	}

	return sliced;
}