From 9c72959cd398909139137b0831a19c2e05161fe2 Mon Sep 17 00:00:00 2001 From: Yura Dupyn <2153100+omedusyo@users.noreply.github.com> Date: Sat, 25 Apr 2026 01:58:35 +0200 Subject: [PATCH] Few helpers. Now `getLineRange` throws on out of bounds line. --- src/index.ts | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index e030add..4fe0547 100644 --- a/src/index.ts +++ b/src/index.ts @@ -240,19 +240,28 @@ export class SourceText { return this.sliceByCp(startCp, endCp); } - getLineRange(line: number): { start: CodePointIndex, end: CodePointIndex } { + + tryGetLineRange(line: number): CodePointSpan | undefined { const lineIndex = line - 1; + if (lineIndex < 0 || lineIndex >= this.lineStarts.length) { - // TODO: This is a bit suspicious. Maybe return undefined? - return { start: 0, end: 0 }; + return undefined; } const start = this.lineStarts[lineIndex]; const end = (lineIndex + 1 < this.lineStarts.length) ? this.lineStarts[lineIndex + 1] : this.#chars.length; - - return { start, end }; + + return rawSpan(start, end); + } + + getLineRange(line: number): { start: CodePointIndex, end: CodePointIndex } { + const range = this.tryGetLineRange(line); + if (range === undefined) { + throw new Error(`Line ${line} is out of bounds (line count: ${this.lineCount})`); + } + return range; } } @@ -308,6 +317,10 @@ export class SourceRegion { return span(loc, loc); } + get codePointSpan(): CodePointSpan { + return rawSpan(this.span.start.index, this.span.end.index); + } + *codePoints(): IterableIterator<[CodePointIndex, CodePoint]> { const start = this.span.start.index; const end = this.span.end.index; @@ -378,6 +391,16 @@ export type SourceLocation = { column: number; // 1-based } +export function containsSpan(outer: CodePointSpan, inner: CodePointSpan): boolean { + return outer.start <= inner.start && inner.end <= outer.end; +} + +export function containsIndex(span: CodePointSpan, index: CodePointIndex): boolean { + return span.start <= index && index < span.end; +} + +// === Cursor === + export class SourceCursor { private index: CodePointIndex; @@ -431,6 +454,11 @@ export class SourceCursor { return this.region.slice(span); } + + location(): SourceLocation { + return this.region.source.getLocation(this.index); + } + moveToNextLineStart(): void { const loc = this.region.source.getLocation(this.index); const nextLine = loc.line + 1;