From 617d33c9ae2fcaaadab27fbc079a52a9c782a15d Mon Sep 17 00:00:00 2001 From: Dylan Piercey Date: Fri, 29 Jul 2022 13:35:24 -0700 Subject: [PATCH] feat: expose position / location / line internal apis --- .changeset/proud-worms-unite.md | 5 +++ src/core/Parser.ts | 17 +++++--- src/index.ts | 3 ++ src/util/util.ts | 72 +++++++++++++++++++++------------ 4 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 .changeset/proud-worms-unite.md diff --git a/.changeset/proud-worms-unite.md b/.changeset/proud-worms-unite.md new file mode 100644 index 00000000..c8e72eca --- /dev/null +++ b/.changeset/proud-worms-unite.md @@ -0,0 +1,5 @@ +--- +"htmljs-parser": minor +--- + +Expose some apis for generating position and location information. diff --git a/src/core/Parser.ts b/src/core/Parser.ts index 8b41d45c..4e6a1bd2 100644 --- a/src/core/Parser.ts +++ b/src/core/Parser.ts @@ -6,8 +6,8 @@ import { Range, ParserOptions as Options, getLines, - getLoc, - getPos, + getLocation, + getPosition, ErrorCode, } from "../internal"; @@ -53,12 +53,19 @@ export class Parser { return this.data.slice(range.start, range.end); } - positionAt(index: number) { - return getPos(this.lines || (this.lines = getLines(this.data)), 0, index); + positionAt(offset: number) { + return getPosition( + this.lines || (this.lines = getLines(this.data)), + offset + ); } locationAt(range: Range) { - return getLoc(this.lines || (this.lines = getLines(this.data)), range); + return getLocation( + this.lines || (this.lines = getLines(this.data)), + range.start, + range.end + ); } enterState

(state: StateDefinition

): P { diff --git a/src/index.ts b/src/index.ts index a9baf194..73fab708 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,9 @@ import { type ParserOptions, type Range, Parser } from "./internal"; export { TagType, ErrorCode, + getLines, + getLocation, + getPosition, type ParserOptions as Handlers, type Position, type Location, diff --git a/src/util/util.ts b/src/util/util.ts index 7a00c9b7..65a96bcf 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -1,5 +1,5 @@ import { CODE, type Parser } from "../internal"; -import { ErrorCode, Location, Position, Range } from "./constants"; +import { ErrorCode, Location, Position } from "./constants"; export function isWhitespaceCode(code: number) { // For all practical purposes, the space character (32) and all the @@ -9,37 +9,33 @@ export function isWhitespaceCode(code: number) { return code <= CODE.SPACE; } -export function getLoc(lines: number[], range: Range): Location { - const start = getPos(lines, 0, range.start); +/** + * Given a source code line offsets, a start offset and an end offset, returns a Location object with line & character information for the start and end offsets. + */ +export function getLocation( + lines: number[], + startOffset: number, + endOffset: number +): Location { + const start = getPosition(lines, startOffset); const end = - range.start === range.end ? start : getPos(lines, start.line, range.end); + startOffset === endOffset + ? start + : getPosAfterLine(lines, start.line, endOffset); return { start, end }; } -export function getPos( - lines: number[], - startLine: number, - index: number -): Position { - let max = lines.length - 1; - let line = startLine; - - while (line < max) { - const mid = (1 + line + max) >>> 1; - - if (lines[mid] <= index) { - line = mid; - } else { - max = mid - 1; - } - } - - return { - line, - character: index - lines[line], - }; +/** + * Given a source code line offsets and an offset, returns a Position object with line & character information. + */ +export function getPosition(lines: number[], offset: number): Position { + return getPosAfterLine(lines, 0, offset); } +/** + * Scan through some source code and generate an array of offsets for each newline. + * Useful for generating line/column information for source code. + */ export function getLines(src: string) { const lines = [0]; for (let i = 0; i < src.length; i++) { @@ -71,3 +67,27 @@ export function htmlEOF(this: Parser) { } } } + +function getPosAfterLine( + lines: number[], + startLine: number, + index: number +): Position { + let max = lines.length - 1; + let line = startLine; + + while (line < max) { + const mid = (1 + line + max) >>> 1; + + if (lines[mid] <= index) { + line = mid; + } else { + max = mid - 1; + } + } + + return { + line, + character: index - lines[line], + }; +}