mirror of
https://github.com/tenrok/BBob.git
synced 2026-06-23 20:40:34 +03:00
add TagNode class for ast, some method names refactor
This commit is contained in:
@@ -12,14 +12,10 @@ const {
|
|||||||
isTagEnd,
|
isTagEnd,
|
||||||
} = require('./Token');
|
} = require('./Token');
|
||||||
|
|
||||||
const {
|
|
||||||
SLASH,
|
|
||||||
getChar,
|
|
||||||
} = require('./char');
|
|
||||||
|
|
||||||
const Tokenizer = require('./Tokenizer');
|
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 {
|
class Parser {
|
||||||
constructor(input, options = {}) {
|
constructor(input, options = {}) {
|
||||||
this.tokenizer = new Tokenizer(input, {
|
this.createTokenizer(input);
|
||||||
onToken: (token) => {
|
|
||||||
this.parseToken(token);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
|
||||||
this.nodes = [];
|
this.nodes = [];
|
||||||
this.nestedNodes = [];
|
this.nestedNodes = [];
|
||||||
this.curTags = [];
|
this.tagNodes = [];
|
||||||
this.curTagsAttrName = [];
|
this.tagNodesAttrName = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
isNestedTag(token) {
|
createTokenizer(input) {
|
||||||
|
this.tokenizer = new Tokenizer(input, {
|
||||||
|
onToken: (token) => {
|
||||||
|
this.parseToken(token);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isTagNested(token) {
|
||||||
return this.tokenizer.isTokenNested(token);
|
return this.tokenizer.isTokenNested(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurTag() {
|
/**
|
||||||
if (this.curTags.length) {
|
* @return {TagNode}
|
||||||
return this.curTags[this.curTags.length - 1];
|
*/
|
||||||
|
getTagNode() {
|
||||||
|
if (this.tagNodes.length) {
|
||||||
|
return this.tagNodes[this.tagNodes.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
createCurTag(token) {
|
createTagNode(token) {
|
||||||
this.curTags.push(createTagNode(getTokenValue(token)));
|
this.tagNodes.push(createTagNode(getTokenValue(token)));
|
||||||
}
|
}
|
||||||
|
|
||||||
createCurTagAttrName(token) {
|
createTagNodeAttrName(token) {
|
||||||
this.curTagsAttrName.push(getTokenValue(token));
|
this.tagNodesAttrName.push(getTokenValue(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurTagAttrName() {
|
getTagNodeAttrName() {
|
||||||
if (this.curTagsAttrName.length) {
|
if (this.tagNodesAttrName.length) {
|
||||||
return this.curTagsAttrName[this.curTagsAttrName.length - 1];
|
return this.tagNodesAttrName[this.tagNodesAttrName.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getCurTag().tag;
|
return this.getTagNode().tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCurTagAttrName() {
|
clearTagNodeAttrName() {
|
||||||
if (this.curTagsAttrName.length) {
|
if (this.tagNodesAttrName.length) {
|
||||||
this.curTagsAttrName.pop();
|
this.tagNodesAttrName.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCurTag() {
|
clearTagNode() {
|
||||||
if (this.curTags.length) {
|
if (this.tagNodes.length) {
|
||||||
this.curTags.pop();
|
this.tagNodes.pop();
|
||||||
|
|
||||||
this.clearCurTagAttrName();
|
this.clearTagNodeAttrName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,20 +107,20 @@ class Parser {
|
|||||||
|
|
||||||
handleTagStart(token) {
|
handleTagStart(token) {
|
||||||
if (isTagStart(token)) {
|
if (isTagStart(token)) {
|
||||||
this.createCurTag(token);
|
this.createTagNode(token);
|
||||||
|
|
||||||
if (this.isNestedTag(token)) {
|
if (this.isTagNested(token)) {
|
||||||
this.nestedNodes.push(this.getCurTag());
|
this.nestedNodes.push(this.getTagNode());
|
||||||
} else {
|
} else {
|
||||||
this.appendNode(this.getCurTag());
|
this.appendNode(this.getTagNode());
|
||||||
this.clearCurTag();
|
this.clearTagNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTagEnd(token) {
|
handleTagEnd(token) {
|
||||||
if (isTagEnd(token)) {
|
if (isTagEnd(token)) {
|
||||||
this.clearCurTag();
|
this.clearTagNode();
|
||||||
|
|
||||||
const lastNestedNode = this.nestedNodes.pop();
|
const lastNestedNode = this.nestedNodes.pop();
|
||||||
|
|
||||||
@@ -144,16 +147,18 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCurTag(token) {
|
handleTagNode(token) {
|
||||||
if (this.getCurTag()) {
|
const tagNode = this.getTagNode();
|
||||||
|
|
||||||
|
if (tagNode) {
|
||||||
if (isAttrNameToken(token)) {
|
if (isAttrNameToken(token)) {
|
||||||
this.createCurTagAttrName(token);
|
this.createTagNodeAttrName(token);
|
||||||
this.getCurTag().attrs[this.getCurTagAttrName()] = null;
|
tagNode.attr(this.getTagNodeAttrName(), null);
|
||||||
} else if (isAttrValueToken(token)) {
|
} else if (isAttrValueToken(token)) {
|
||||||
this.getCurTag().attrs[this.getCurTagAttrName()] = getTokenValue(token);
|
tagNode.attr(this.getTagNodeAttrName(), getTokenValue(token));
|
||||||
this.clearCurTagAttrName();
|
this.clearTagNodeAttrName();
|
||||||
} else if (isTextToken(token)) {
|
} else if (isTextToken(token)) {
|
||||||
this.getCurTag().content.push(getTokenValue(token));
|
tagNode.append(getTokenValue(token));
|
||||||
}
|
}
|
||||||
} else if (isTextToken(token)) {
|
} else if (isTextToken(token)) {
|
||||||
this.appendNode(getTokenValue(token));
|
this.appendNode(getTokenValue(token));
|
||||||
@@ -162,7 +167,7 @@ class Parser {
|
|||||||
|
|
||||||
parseToken(token) {
|
parseToken(token) {
|
||||||
this.handleTagToken(token);
|
this.handleTagToken(token);
|
||||||
this.handleCurTag(token);
|
this.handleTagNode(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
parse() {
|
parse() {
|
||||||
@@ -184,24 +189,6 @@ class Parser {
|
|||||||
return this.nodes;
|
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) {
|
isAllowedTag(value) {
|
||||||
if (this.options.onlyAllowTags && this.options.onlyAllowTags.length) {
|
if (this.options.onlyAllowTags && this.options.onlyAllowTags.length) {
|
||||||
return this.options.onlyAllowTags.indexOf(value) >= 0;
|
return this.options.onlyAllowTags.indexOf(value) >= 0;
|
||||||
@@ -211,7 +198,5 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new Parser('[Verse 2]').parse();
|
|
||||||
|
|
||||||
module.exports = Parser;
|
module.exports = Parser;
|
||||||
module.exports.createTagNode = createTagNode;
|
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