Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: expose position / location / line internal apis #125

Merged
merged 1 commit into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/proud-worms-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"htmljs-parser": minor
---

Expose some apis for generating position and location information.
17 changes: 12 additions & 5 deletions src/core/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
Range,
ParserOptions as Options,
getLines,
getLoc,
getPos,
getLocation,
getPosition,
ErrorCode,
} from "../internal";

Expand Down Expand Up @@ -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<P extends Meta>(state: StateDefinition<P>): P {
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
72 changes: 46 additions & 26 deletions src/util/util.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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++) {
Expand Down Expand Up @@ -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],
};
}