mirror of
https://github.com/tenrok/BBob.git
synced 2026-05-15 11:59:37 +03:00
add TagNode class for ast, some method names refactor
This commit is contained in:
@@ -12,14 +12,10 @@ const {
|
||||
isTagEnd,
|
||||
} = require('./Token');
|
||||
|
||||
const {
|
||||
SLASH,
|
||||
getChar,
|
||||
} = require('./char');
|
||||
|
||||
const Tokenizer = require('./Tokenizer');
|
||||
const TagNode = require('./TagNode');
|
||||
|
||||
const createTagNode = (tag, attrs = {}, content = []) => ({ tag, attrs, content });
|
||||
const createTagNode = (tag, attrs = {}, content = []) => new TagNode(tag, attrs, content);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,59 +29,66 @@ const createTagNode = (tag, attrs = {}, content = []) => ({ tag, attrs, content
|
||||
*/
|
||||
class Parser {
|
||||
constructor(input, options = {}) {
|
||||
this.tokenizer = new Tokenizer(input, {
|
||||
onToken: (token) => {
|
||||
this.parseToken(token);
|
||||
},
|
||||
});
|
||||
this.createTokenizer(input);
|
||||
|
||||
this.options = options;
|
||||
|
||||
this.nodes = [];
|
||||
this.nestedNodes = [];
|
||||
this.curTags = [];
|
||||
this.curTagsAttrName = [];
|
||||
this.tagNodes = [];
|
||||
this.tagNodesAttrName = [];
|
||||
}
|
||||
|
||||
isNestedTag(token) {
|
||||
createTokenizer(input) {
|
||||
this.tokenizer = new Tokenizer(input, {
|
||||
onToken: (token) => {
|
||||
this.parseToken(token);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
isTagNested(token) {
|
||||
return this.tokenizer.isTokenNested(token);
|
||||
}
|
||||
|
||||
getCurTag() {
|
||||
if (this.curTags.length) {
|
||||
return this.curTags[this.curTags.length - 1];
|
||||
/**
|
||||
* @return {TagNode}
|
||||
*/
|
||||
getTagNode() {
|
||||
if (this.tagNodes.length) {
|
||||
return this.tagNodes[this.tagNodes.length - 1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
createCurTag(token) {
|
||||
this.curTags.push(createTagNode(getTokenValue(token)));
|
||||
createTagNode(token) {
|
||||
this.tagNodes.push(createTagNode(getTokenValue(token)));
|
||||
}
|
||||
|
||||
createCurTagAttrName(token) {
|
||||
this.curTagsAttrName.push(getTokenValue(token));
|
||||
createTagNodeAttrName(token) {
|
||||
this.tagNodesAttrName.push(getTokenValue(token));
|
||||
}
|
||||
|
||||
getCurTagAttrName() {
|
||||
if (this.curTagsAttrName.length) {
|
||||
return this.curTagsAttrName[this.curTagsAttrName.length - 1];
|
||||
getTagNodeAttrName() {
|
||||
if (this.tagNodesAttrName.length) {
|
||||
return this.tagNodesAttrName[this.tagNodesAttrName.length - 1];
|
||||
}
|
||||
|
||||
return this.getCurTag().tag;
|
||||
return this.getTagNode().tag;
|
||||
}
|
||||
|
||||
clearCurTagAttrName() {
|
||||
if (this.curTagsAttrName.length) {
|
||||
this.curTagsAttrName.pop();
|
||||
clearTagNodeAttrName() {
|
||||
if (this.tagNodesAttrName.length) {
|
||||
this.tagNodesAttrName.pop();
|
||||
}
|
||||
}
|
||||
|
||||
clearCurTag() {
|
||||
if (this.curTags.length) {
|
||||
this.curTags.pop();
|
||||
clearTagNode() {
|
||||
if (this.tagNodes.length) {
|
||||
this.tagNodes.pop();
|
||||
|
||||
this.clearCurTagAttrName();
|
||||
this.clearTagNodeAttrName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,20 +107,20 @@ class Parser {
|
||||
|
||||
handleTagStart(token) {
|
||||
if (isTagStart(token)) {
|
||||
this.createCurTag(token);
|
||||
this.createTagNode(token);
|
||||
|
||||
if (this.isNestedTag(token)) {
|
||||
this.nestedNodes.push(this.getCurTag());
|
||||
if (this.isTagNested(token)) {
|
||||
this.nestedNodes.push(this.getTagNode());
|
||||
} else {
|
||||
this.appendNode(this.getCurTag());
|
||||
this.clearCurTag();
|
||||
this.appendNode(this.getTagNode());
|
||||
this.clearTagNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleTagEnd(token) {
|
||||
if (isTagEnd(token)) {
|
||||
this.clearCurTag();
|
||||
this.clearTagNode();
|
||||
|
||||
const lastNestedNode = this.nestedNodes.pop();
|
||||
|
||||
@@ -144,16 +147,18 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
handleCurTag(token) {
|
||||
if (this.getCurTag()) {
|
||||
handleTagNode(token) {
|
||||
const tagNode = this.getTagNode();
|
||||
|
||||
if (tagNode) {
|
||||
if (isAttrNameToken(token)) {
|
||||
this.createCurTagAttrName(token);
|
||||
this.getCurTag().attrs[this.getCurTagAttrName()] = null;
|
||||
this.createTagNodeAttrName(token);
|
||||
tagNode.attr(this.getTagNodeAttrName(), null);
|
||||
} else if (isAttrValueToken(token)) {
|
||||
this.getCurTag().attrs[this.getCurTagAttrName()] = getTokenValue(token);
|
||||
this.clearCurTagAttrName();
|
||||
tagNode.attr(this.getTagNodeAttrName(), getTokenValue(token));
|
||||
this.clearTagNodeAttrName();
|
||||
} else if (isTextToken(token)) {
|
||||
this.getCurTag().content.push(getTokenValue(token));
|
||||
tagNode.append(getTokenValue(token));
|
||||
}
|
||||
} else if (isTextToken(token)) {
|
||||
this.appendNode(getTokenValue(token));
|
||||
@@ -162,7 +167,7 @@ class Parser {
|
||||
|
||||
parseToken(token) {
|
||||
this.handleTagToken(token);
|
||||
this.handleCurTag(token);
|
||||
this.handleTagNode(token);
|
||||
}
|
||||
|
||||
parse() {
|
||||
@@ -184,24 +189,6 @@ class Parser {
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
findNestedTags() {
|
||||
const tags = (this.tokens || []).filter(isTagToken).reduce((acc, token) => {
|
||||
acc[getTokenValue(token)] = true;
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const closeChar = getChar(SLASH);
|
||||
|
||||
return Object.keys(tags).reduce((arr, key) => {
|
||||
if (tags[key] && tags[closeChar + key]) {
|
||||
arr.push(key);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}, []);
|
||||
}
|
||||
|
||||
isAllowedTag(value) {
|
||||
if (this.options.onlyAllowTags && this.options.onlyAllowTags.length) {
|
||||
return this.options.onlyAllowTags.indexOf(value) >= 0;
|
||||
@@ -211,7 +198,5 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
new Parser('[Verse 2]').parse();
|
||||
|
||||
module.exports = Parser;
|
||||
module.exports.createTagNode = createTagNode;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
const {
|
||||
getChar, N, CLOSE_BRAKET, OPEN_BRAKET, SLASH,
|
||||
} = require('./char');
|
||||
|
||||
const EOL = getChar(N);
|
||||
const isNode = el => typeof el === 'object' && el.tag;
|
||||
const isStringNode = el => typeof el === 'string';
|
||||
const isEOL = el => el === EOL;
|
||||
|
||||
const getNodeLength = (node) => {
|
||||
if (isNode(node)) {
|
||||
return node.content.reduce((count, contentNode) => count + getNodeLength(contentNode), 0);
|
||||
} else if (isStringNode(node)) {
|
||||
return node.length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
const appendToNode = (node, value) => {
|
||||
node.content.push(value);
|
||||
};
|
||||
|
||||
class TagNode {
|
||||
constructor(tag, attrs, content) {
|
||||
this.tag = tag;
|
||||
this.attrs = attrs;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
attr(name, value) {
|
||||
if (typeof value !== 'undefined') {
|
||||
this.attrs[name] = value;
|
||||
}
|
||||
|
||||
return this.attrs[name];
|
||||
}
|
||||
|
||||
append(value) {
|
||||
return appendToNode(this, value);
|
||||
}
|
||||
|
||||
get length() {
|
||||
return getNodeLength(this);
|
||||
}
|
||||
|
||||
toString() {
|
||||
const OB = getChar(OPEN_BRAKET);
|
||||
const CB = getChar(CLOSE_BRAKET);
|
||||
|
||||
return OB + this.tag + CB + this.content.reduce((r, node) => r + node.toString(), '') + OB + getChar(SLASH) + this.tag + CB;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TagNode;
|
||||
module.exports.isNode = isNode;
|
||||
module.exports.isStringNode = isStringNode;
|
||||
module.exports.isEOL = isEOL;
|
||||
module.exports.appendToNode = appendToNode;
|
||||
Reference in New Issue
Block a user