Add line number function to JS document parser.
This commit is contained in:
parent
8dca90037a
commit
70200a4091
1522
packages/js/package-lock.json
generated
Normal file
1522
packages/js/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@terrace-lang/js",
|
||||
"description": "Terrace is a simple structured data syntax for configuration, content authoring, and DSLs.",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
|
@ -1,16 +1,17 @@
|
||||
import type { Reader } from './readers/reader.js'
|
||||
import { createLineData, parseLine } from './parser.js'
|
||||
import type { Reader } from "./readers/reader.js";
|
||||
import { createLineData, parseLine } from "./parser.js";
|
||||
|
||||
// Container for a handful of convenience functions for parsing documents
|
||||
// Obtained from useDocument() below
|
||||
export type Document = {
|
||||
next: (levelScope?: number) => Promise<boolean>
|
||||
level: () => number,
|
||||
line: (startOffset?: number) => string,
|
||||
head: () => string,
|
||||
tail: () => string,
|
||||
match: (matchValue: string) => boolean
|
||||
}
|
||||
next: (levelScope?: number) => Promise<boolean>;
|
||||
level: () => number;
|
||||
lineNumber: () => number;
|
||||
line: (startOffset?: number) => string;
|
||||
head: () => string;
|
||||
tail: () => string;
|
||||
match: (matchValue: string) => boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides a simple set of convenience functions around parseLine for more ergonomic parsing of Terrace documents
|
||||
@ -19,15 +20,19 @@ export type Document = {
|
||||
* @param {String} indent The character used for indentation in the document. Only a single character is permitted
|
||||
* @returns {Document} A set of convenience functions for iterating through and parsing a document line by line
|
||||
*/
|
||||
export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
if (indent.length !== 1) throw new Error(`Terrace currently only allows single-character indent strings - you passed "${indent}"`)
|
||||
export function useDocument(reader: Reader, indent: string = " "): Document {
|
||||
if (indent.length !== 1)
|
||||
throw new Error(
|
||||
`Terrace currently only allows single-character indent strings - you passed "${indent}"`
|
||||
);
|
||||
|
||||
const lineData = createLineData(indent)
|
||||
let currLine = ''
|
||||
const lineData = createLineData(indent);
|
||||
let currLine = "";
|
||||
let currLineNumber = -1;
|
||||
|
||||
// If `repeatCurrentLine` is `true`, the following call to `next()` will repeat the current line in
|
||||
// the document and set `repeatCurrentLine` back to `false`
|
||||
let repeatCurrentLine = false
|
||||
let repeatCurrentLine = false;
|
||||
/**
|
||||
* Advances the current position in the terrace document and populates lineData
|
||||
* with the parsed information from that line
|
||||
@ -54,28 +59,29 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
async function next(levelScope: number = -1): Promise<boolean> {
|
||||
// Repeat the current line instead of parsing a new one if the previous call to next()
|
||||
// determined the current line to be out of its scope.
|
||||
if (repeatCurrentLine) repeatCurrentLine = false
|
||||
if (repeatCurrentLine) repeatCurrentLine = false;
|
||||
// Otherwise parse the line normally.
|
||||
else {
|
||||
// Load the next line from the line reader.
|
||||
const line = await reader()
|
||||
const line = await reader();
|
||||
// If there are no more lines, bail out.
|
||||
if (line == null) return false
|
||||
if (line == null) return false;
|
||||
|
||||
// Populate lineData with parsed information from the current line.
|
||||
currLine = line
|
||||
parseLine(currLine, lineData)
|
||||
currLine = line;
|
||||
currLineNumber++;
|
||||
parseLine(currLine, lineData);
|
||||
}
|
||||
|
||||
// If we shouldn't be handling this line, make the following call to next() repeat the current line.
|
||||
// Allows a child loop to look forward, determine that the next line will be outside its purview,
|
||||
// and return control to the calling loop transparently without additional logic.
|
||||
if (level() <= levelScope) {
|
||||
repeatCurrentLine = true
|
||||
return false
|
||||
repeatCurrentLine = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,7 +97,14 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
* ```
|
||||
* @returns {number} The indent level of the current line
|
||||
*/
|
||||
const level = (): number => lineData.level
|
||||
const level = (): number => lineData.level;
|
||||
|
||||
/**
|
||||
* Get the current line number, zero-indexed from first line read.
|
||||
* @returns {number} The current line number, starting from zero.
|
||||
*/
|
||||
const lineNumber = (): number => currLineNumber;
|
||||
|
||||
/**
|
||||
* Get a string with the current line contents. Skips all indent characters by default, but this can be configured with `startOffset`
|
||||
*
|
||||
@ -109,7 +122,9 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
* @param {number} startOffset How many indent characters to skip before outputting the line contents. Defaults to the current indent level
|
||||
* @returns {string} The line contents starting from `startOffset`
|
||||
*/
|
||||
const line = (startOffset: number = lineData.level): string => currLine.slice(startOffset)
|
||||
const line = (startOffset: number = lineData.level): string =>
|
||||
currLine.slice(startOffset);
|
||||
|
||||
/**
|
||||
* Get the first "word" of a line, starting from the first non-indent character to the first space or end of the line
|
||||
* Often used for deciding how to parse a block.
|
||||
@ -123,7 +138,9 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
* ```
|
||||
* @returns {string} The `head` portion (first word) of a line
|
||||
*/
|
||||
const head = (): string => currLine.slice(lineData.offsetHead, lineData.offsetTail)
|
||||
const head = (): string =>
|
||||
currLine.slice(lineData.offsetHead, lineData.offsetTail);
|
||||
|
||||
/**
|
||||
* Get all text following the first "word" of a line, starting from the first character after the space at the end of `head()`
|
||||
*
|
||||
@ -136,7 +153,7 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
* ```
|
||||
* @returns {string} The remainder of the line following the `head()` portion, with no leading space
|
||||
*/
|
||||
const tail = (): string => currLine.slice(lineData.offsetTail + 1) // Skip the space
|
||||
const tail = (): string => currLine.slice(lineData.offsetTail + 1); // Skip the space
|
||||
/**
|
||||
* Quickly check if the current line head matches a specified value
|
||||
*
|
||||
@ -154,14 +171,15 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
* @param {string} matchValue A string to check against `head()` for equality
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const match = (matchValue: string): boolean => matchValue === head()
|
||||
const match = (matchValue: string): boolean => matchValue === head();
|
||||
|
||||
return {
|
||||
next,
|
||||
level,
|
||||
line,
|
||||
lineNumber,
|
||||
head,
|
||||
tail,
|
||||
match
|
||||
}
|
||||
match,
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user