mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-08 16:36:15 +00:00
122 lines
2.3 KiB
JavaScript
122 lines
2.3 KiB
JavaScript
import HTMLRenderer from './html_renderer';
|
|
|
|
class TokenTree {
|
|
constructor() {
|
|
this.rootNode = { children: [] };
|
|
this.stack = [this.rootNode];
|
|
}
|
|
|
|
get top() {
|
|
return this.stack[this.stack.length - 1];
|
|
}
|
|
|
|
get root() { return this.rootNode; }
|
|
|
|
add(node) {
|
|
this.top.children.push(node);
|
|
}
|
|
|
|
openNode(kind) {
|
|
const node = { kind, children: [] };
|
|
this.add(node);
|
|
this.stack.push(node);
|
|
}
|
|
|
|
closeNode() {
|
|
if (this.stack.length > 1) {
|
|
return this.stack.pop();
|
|
}
|
|
}
|
|
|
|
closeAllNodes() {
|
|
while (this.closeNode());
|
|
}
|
|
|
|
toJSON() {
|
|
return JSON.stringify(this.rootNode, null, 4);
|
|
}
|
|
|
|
walk(builder) {
|
|
return this.constructor._walk(builder, this.rootNode);
|
|
}
|
|
|
|
static _walk(builder, node) {
|
|
if (typeof node === "string") {
|
|
builder.addText(node);
|
|
} else if (node.children) {
|
|
builder.openNode(node);
|
|
node.children.forEach((child) => this._walk(builder, child));
|
|
builder.closeNode(node);
|
|
}
|
|
return builder;
|
|
}
|
|
|
|
static _collapse(node) {
|
|
if (!node.children) {
|
|
return;
|
|
}
|
|
if (node.children.every(el => typeof el === "string")) {
|
|
node.text = node.children.join("");
|
|
delete node.children;
|
|
} else {
|
|
node.children.forEach((child) => {
|
|
if (typeof child === "string") return;
|
|
TokenTree._collapse(child);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Currently this is all private API, but this is the minimal API necessary
|
|
that an Emitter must implement to fully support the parser.
|
|
|
|
Minimal interface:
|
|
|
|
- addKeyword(text, kind)
|
|
- addText(text)
|
|
- addSublanguage(emitter, subLanguageName)
|
|
- finalize()
|
|
- openNode(kind)
|
|
- closeNode()
|
|
- closeAllNodes()
|
|
- toHTML()
|
|
|
|
*/
|
|
export default class TokenTreeEmitter extends TokenTree {
|
|
constructor(options) {
|
|
super();
|
|
this.options = options;
|
|
}
|
|
|
|
addKeyword(text, kind) {
|
|
if (text === "") { return; }
|
|
|
|
this.openNode(kind);
|
|
this.addText(text);
|
|
this.closeNode();
|
|
}
|
|
|
|
addText(text) {
|
|
if (text === "") { return; }
|
|
|
|
this.add(text);
|
|
}
|
|
|
|
addSublanguage(emitter, name) {
|
|
const node = emitter.root;
|
|
node.kind = name;
|
|
node.sublanguage = true;
|
|
this.add(node);
|
|
}
|
|
|
|
toHTML() {
|
|
const renderer = new HTMLRenderer(this, this.options);
|
|
return renderer.value();
|
|
}
|
|
|
|
finalize() {
|
|
return true;
|
|
}
|
|
}
|