mirror of
https://github.com/tenrok/BBob.git
synced 2026-06-20 20:00:33 +03:00
* feat(parser): write test for only allowed tags parsing * chore(parser): rename only allowed test * fix(parser): only allowed tag rendering * fix(plugin-helper): add new TagNode toString tests
This commit is contained in:
committed by
GitHub
parent
f28f19e64c
commit
a16b9f73b0
@@ -1,4 +1,5 @@
|
|||||||
import TagNode from '@bbob/plugin-helper/lib/TagNode';
|
import TagNode from '@bbob/plugin-helper/lib/TagNode';
|
||||||
|
import { isTagNode } from '@bbob/plugin-helper';
|
||||||
import { createLexer } from './lexer';
|
import { createLexer } from './lexer';
|
||||||
import { createList } from './utils';
|
import { createList } from './utils';
|
||||||
|
|
||||||
@@ -57,8 +58,25 @@ const parse = (input, opts = {}) => {
|
|||||||
return nestedTagsMap[token.getValue()];
|
return nestedTagsMap[token.getValue()];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tagName
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
const isTagNested = (tagName) => !!nestedTagsMap[tagName];
|
const isTagNested = (tagName) => !!nestedTagsMap[tagName];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {String} value
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
const isAllowedTag = (value) => {
|
||||||
|
if (options.onlyAllowTags && options.onlyAllowTags.length) {
|
||||||
|
return options.onlyAllowTags.indexOf(value) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flushes temp tag nodes and its attributes buffers
|
* Flushes temp tag nodes and its attributes buffers
|
||||||
* @private
|
* @private
|
||||||
@@ -86,29 +104,24 @@ const parse = (input, opts = {}) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {TagNode} tag
|
* @param {string|TagNode} node
|
||||||
*/
|
*/
|
||||||
const appendNodes = (tag) => {
|
const appendNodes = (node) => {
|
||||||
const items = getNodes();
|
const items = getNodes();
|
||||||
|
|
||||||
if (Array.isArray(items)) {
|
if (Array.isArray(items)) {
|
||||||
items.push(tag);
|
if (isTagNode(node)) {
|
||||||
|
if (isAllowedTag(node.tag)) {
|
||||||
|
items.push(node.toTagNode());
|
||||||
|
} else {
|
||||||
|
items.push(node.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
items.push(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @param {String} value
|
|
||||||
* @return {boolean}
|
|
||||||
*/
|
|
||||||
const isAllowedTag = (value) => {
|
|
||||||
if (options.onlyAllowTags && options.onlyAllowTags.length) {
|
|
||||||
return options.onlyAllowTags.indexOf(value) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {Token} token
|
* @param {Token} token
|
||||||
@@ -124,7 +137,7 @@ const parse = (input, opts = {}) => {
|
|||||||
if (isNested) {
|
if (isNested) {
|
||||||
nestedNodes.push(tagNode);
|
nestedNodes.push(tagNode);
|
||||||
} else {
|
} else {
|
||||||
appendNodes(tagNode);
|
appendNodes(tagNode, token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,8 +151,8 @@ const parse = (input, opts = {}) => {
|
|||||||
const lastNestedNode = nestedNodes.flushLast();
|
const lastNestedNode = nestedNodes.flushLast();
|
||||||
|
|
||||||
if (lastNestedNode) {
|
if (lastNestedNode) {
|
||||||
appendNodes(lastNestedNode);
|
appendNodes(lastNestedNode, token);
|
||||||
} else if (options.onError) {
|
} else if (typeof options.onError === 'function') {
|
||||||
const tag = token.getValue();
|
const tag = token.getValue();
|
||||||
const line = token.getLine();
|
const line = token.getLine();
|
||||||
const column = token.getColumn();
|
const column = token.getColumn();
|
||||||
@@ -217,7 +230,7 @@ const parse = (input, opts = {}) => {
|
|||||||
* @param {Token} token
|
* @param {Token} token
|
||||||
*/
|
*/
|
||||||
const onToken = (token) => {
|
const onToken = (token) => {
|
||||||
if (token.isTag() && isAllowedTag(token.getName())) {
|
if (token.isTag()) {
|
||||||
handleTag(token);
|
handleTag(token);
|
||||||
} else {
|
} else {
|
||||||
handleNode(token);
|
handleNode(token);
|
||||||
|
|||||||
@@ -119,6 +119,32 @@ describe('Parser', () => {
|
|||||||
expect(onError).toHaveBeenCalled();
|
expect(onError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('parse only allowed tags with params', () => {
|
||||||
|
const options = {
|
||||||
|
onlyAllowTags: ['b', 'i', 'u']
|
||||||
|
};
|
||||||
|
const ast = parse('hello [blah foo="bar"]world[/blah]', options);
|
||||||
|
|
||||||
|
expectOutput(ast, [
|
||||||
|
'hello',
|
||||||
|
' ',
|
||||||
|
'[blah foo="bar"]world[/blah]',
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
|
test('parse only allowed tags with named param', () => {
|
||||||
|
const options = {
|
||||||
|
onlyAllowTags: ['b', 'i', 'u']
|
||||||
|
};
|
||||||
|
const ast = parse('hello [blah="bar"]world[/blah]', options);
|
||||||
|
|
||||||
|
expectOutput(ast, [
|
||||||
|
'hello',
|
||||||
|
' ',
|
||||||
|
'[blah="bar"]world[/blah]',
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
describe('html', () => {
|
describe('html', () => {
|
||||||
const parseHTML = input => parse(input, { openTag: '<', closeTag: '>' });
|
const parseHTML = input => parse(input, { openTag: '<', closeTag: '>' });
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
import { OPEN_BRAKET, CLOSE_BRAKET, SLASH } from './char';
|
import { OPEN_BRAKET, CLOSE_BRAKET, SLASH } from './char';
|
||||||
import { getNodeLength, appendToNode } from './index';
|
import {
|
||||||
|
getNodeLength, appendToNode, attrsToString, attrValue, getUniqAttr,
|
||||||
|
} from './index';
|
||||||
|
|
||||||
|
const getTagAttrs = (tag, params) => {
|
||||||
|
const uniqAattr = getUniqAttr(params);
|
||||||
|
|
||||||
|
if (uniqAattr) {
|
||||||
|
const tagAttr = attrValue(tag, uniqAattr);
|
||||||
|
const attrs = { ...params };
|
||||||
|
|
||||||
|
delete attrs[uniqAattr];
|
||||||
|
|
||||||
|
const attrsStr = attrsToString(attrs);
|
||||||
|
|
||||||
|
return `${tagAttr}${attrsStr}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${tag}${attrsToString(params)}`;
|
||||||
|
};
|
||||||
|
|
||||||
class TagNode {
|
class TagNode {
|
||||||
constructor(tag, attrs, content) {
|
constructor(tag, attrs, content) {
|
||||||
this.tag = tag.toLowerCase();
|
this.tag = tag;
|
||||||
this.attrs = attrs;
|
this.attrs = attrs;
|
||||||
this.content = [].concat(content);
|
this.content = [].concat(content);
|
||||||
}
|
}
|
||||||
@@ -24,11 +43,22 @@ class TagNode {
|
|||||||
return getNodeLength(this);
|
return getNodeLength(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toTagNode() {
|
||||||
|
return new TagNode(this.tag.toLowerCase(), this.attrs, this.content);
|
||||||
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
const OB = OPEN_BRAKET;
|
const OB = OPEN_BRAKET;
|
||||||
const CB = CLOSE_BRAKET;
|
const CB = CLOSE_BRAKET;
|
||||||
|
const isEmpty = this.content.length === 0;
|
||||||
|
const content = this.content.reduce((r, node) => r + node.toString(), '');
|
||||||
|
const tagAttrs = getTagAttrs(this.tag, this.attrs);
|
||||||
|
|
||||||
return OB + this.tag + CB + this.content.reduce((r, node) => r + node.toString(), '') + OB + SLASH + this.tag + CB;
|
if (isEmpty) {
|
||||||
|
return `${OB}${tagAttrs}${CB}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${OB}${tagAttrs}${CB}${content}${OB}${SLASH}${this.tag}${CB}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,35 @@ describe('@bbob/plugin-helper/lib/TagNode', () => {
|
|||||||
expect(TagNode.isOf(tagNode, 'test')).toBe(true);
|
expect(TagNode.isOf(tagNode, 'test')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toString', () => {
|
describe('toString', () => {
|
||||||
const tagNode = TagNode.create('test', {test: 1}, ['Hello']);
|
test('tag with content and params', () => {
|
||||||
|
const tagNode = TagNode.create('test', {test: 1}, ['Hello']);
|
||||||
|
|
||||||
expect(String(tagNode)).toBe('[test]Hello[/test]');
|
expect(String(tagNode)).toBe('[test test="1"]Hello[/test]');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('tag with content and uniq attr', () => {
|
||||||
|
const tagNode = TagNode.create('test', {test: 'test'}, ['Hello']);
|
||||||
|
|
||||||
|
expect(String(tagNode)).toBe('[test="test"]Hello[/test]');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('tag without content', () => {
|
||||||
|
const tagNode = TagNode.create('test');
|
||||||
|
|
||||||
|
expect(String(tagNode)).toBe('[test]');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('tag without content', () => {
|
||||||
|
const tagNode = TagNode.create('test', {}, 'Content');
|
||||||
|
|
||||||
|
expect(String(tagNode)).toBe('[test]Content[/test]');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('tag with snakeCase', () => {
|
||||||
|
const tagNode = TagNode.create('snakeCaseTag');
|
||||||
|
|
||||||
|
expect(String(tagNode)).toBe('[snakeCaseTag]');
|
||||||
|
});
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user