2
0
mirror of https://github.com/tenrok/BBob.git synced 2026-06-17 19:21:20 +03:00

feat: add start and end positions of tag nodes (#246)

Closes #134

* feat: Add start and end positions of tag nodes

Improves accuracy of row/col error reporting. Now targets the start of the relevant token instead of the end.

* Simplify language for TagNode and Token

* Update static TagNode.create to ingest setStart() logic

improve readability of end pos offset for no attr tags
This commit is contained in:
Steven Chang
2024-08-01 00:42:29 -07:00
committed by GitHub
parent 0beab56d7f
commit 40848747d4
13 changed files with 929 additions and 386 deletions
+41 -20
View File
@@ -1,4 +1,4 @@
import type { NodeContent, TagNodeObject, TagNodeTree } from "@bbob/types";
import type { NodeContent, TagNodeObject, TagNodeTree, TagPosition } from "@bbob/types";
import { OPEN_BRAKET, CLOSE_BRAKET, SLASH } from './char';
import {
@@ -30,38 +30,40 @@ const getTagAttrs = <AttrValue>(tag: string, params: Record<string, AttrValue>)
const renderContent = (content: TagNodeTree, openTag: string, closeTag: string) => {
const toString = (node: NodeContent) => {
if (isTagNode(node)) {
return node.toString({ openTag, closeTag })
return node.toString({ openTag, closeTag });
}
return String(node)
}
return String(node);
};
if (Array.isArray(content)) {
return content.reduce<string>((r, node) => {
if (node !== null) {
return r + toString(node)
return r + toString(node);
}
return r
}, '')
return r;
}, '');
}
if (content) {
return toString(content)
return toString(content);
}
return null
}
return null;
};
export class TagNode<TagValue extends any = any> implements TagNodeObject {
public readonly tag: string | TagValue
public attrs: Record<string, unknown>
public content: TagNodeTree
public readonly tag: string | TagValue;
public attrs: Record<string, unknown>;
public content: TagNodeTree;
public start?: TagPosition;
public end?: TagPosition;
constructor(tag: string | TagValue, attrs: Record<string, unknown>, content: TagNodeTree) {
this.tag = tag;
this.attrs = attrs;
this.content = content
this.content = content;
}
attr(name: string, value?: unknown) {
@@ -76,6 +78,14 @@ export class TagNode<TagValue extends any = any> implements TagNodeObject {
return appendToNode(this, value);
}
setStart(value: TagPosition) {
this.start = value;
}
setEnd(value: TagPosition) {
this.end = value;
}
get length(): number {
return getNodeLength(this);
}
@@ -91,25 +101,36 @@ export class TagNode<TagValue extends any = any> implements TagNodeObject {
}
toTagNode() {
return new TagNode(String(this.tag).toLowerCase(), this.attrs, this.content);
const newNode = new TagNode(String(this.tag).toLowerCase(), this.attrs, this.content);
if (this.start) {
newNode.setStart(this.start);
}
if (this.end) {
newNode.setEnd(this.end);
}
return newNode;
}
toString({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}): string {
const content = this.content ? renderContent(this.content, openTag, closeTag) : ''
const content = this.content ? renderContent(this.content, openTag, closeTag) : '';
const tagStart = this.toTagStart({ openTag, closeTag });
if (this.content === null || Array.isArray(this.content) && this.content.length === 0) {
if (this.content === null || Array.isArray(this.content) && this.content.length === 0) {
return tagStart;
}
return `${tagStart}${content}${this.toTagEnd({ openTag, closeTag })}`;
}
static create(tag: string, attrs: Record<string, unknown> = {}, content: TagNodeTree = null) {
return new TagNode(tag, attrs, content)
static create(tag: string, attrs: Record<string, unknown> = {}, content: TagNodeTree = null, start?: TagPosition) {
const node = new TagNode(tag, attrs, content);
if (start) {
node.setStart(start);
}
return node;
}
static isOf(node: TagNode, type: string) {
return (node.tag === type)
return (node.tag === type);
}
}