From 70ff2e6660bb507f6ed57cb91e850b3879bdb7eb Mon Sep 17 00:00:00 2001 From: Nikolay Kostyurin Date: Wed, 16 Dec 2020 23:51:28 +0200 Subject: [PATCH] fix(parser): dont process nested tags as string if parent is not allowed (#84) * fix(parser): dont process nested tags as string if parent is not allowed * fix(plugin-helper): toString method with default params --- packages/bbob-parser/src/parse.js | 17 ++- packages/bbob-parser/test/parse.test.js | 143 ++++++++++++++------- packages/bbob-plugin-helper/src/TagNode.js | 22 +++- 3 files changed, 127 insertions(+), 55 deletions(-) diff --git a/packages/bbob-parser/src/parse.js b/packages/bbob-parser/src/parse.js index e6ecb323..111f74cf 100644 --- a/packages/bbob-parser/src/parse.js +++ b/packages/bbob-parser/src/parse.js @@ -1,4 +1,5 @@ import TagNode from '@bbob/plugin-helper/lib/TagNode'; +import { CLOSE_BRAKET, OPEN_BRAKET } from '@bbob/plugin-helper/lib/char'; import { isTagNode } from '@bbob/plugin-helper/lib/index'; import { createLexer } from './lexer'; import { createList } from './utils'; @@ -16,6 +17,8 @@ import { createList } from './utils'; */ const parse = (input, opts = {}) => { const options = opts; + const openTag = options.openTag || OPEN_BRAKET; + const closeTag = options.closeTag || CLOSE_BRAKET; let tokenizer = null; @@ -114,7 +117,15 @@ const parse = (input, opts = {}) => { if (isAllowedTag(node.tag)) { items.push(node.toTagNode()); } else { - items.push(node.toString()); + items.push(node.toTagStart({ openTag, closeTag })); + + if (node.content.length) { + node.content.forEach((item) => { + items.push(item); + }); + + items.push(node.toTagEnd({ openTag, closeTag })); + } } } else { items.push(node); @@ -240,8 +251,8 @@ const parse = (input, opts = {}) => { tokenizer = (opts.createTokenizer ? opts.createTokenizer : createLexer)(input, { onToken, onlyAllowTags: options.onlyAllowTags, - openTag: options.openTag, - closeTag: options.closeTag, + openTag, + closeTag, enableEscapeTags: options.enableEscapeTags, }); diff --git a/packages/bbob-parser/test/parse.test.js b/packages/bbob-parser/test/parse.test.js index 6f5c173d..bc981772 100644 --- a/packages/bbob-parser/test/parse.test.js +++ b/packages/bbob-parser/test/parse.test.js @@ -25,27 +25,106 @@ describe('Parser', () => { expectOutput(ast, output); }); - test('parse only allowed tags', () => { - const ast = parse('[h1 name=value]Foo [Bar] [/h1]', { - onlyAllowTags: ['h1'] + describe('onlyAllowTags', () => { + test('parse only allowed tags', () => { + const ast = parse('[h1 name=value]Foo [Bar] [/h1]', { + onlyAllowTags: ['h1'] + }); + const output = [ + { + tag: 'h1', + attrs: { + name: 'value', + }, + content: [ + 'Foo', + ' ', + '[Bar]', + ' ' + ], + }, + ]; + + expectOutput(ast, output); }); - const output = [ - { - tag: 'h1', - attrs: { - name: 'value', + + 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]' + ]) + }); + + test('parse only allowed tags inside disabled tags', () => { + const ast = parse('[tab] [ch]E[/ch]\nA cripple walks amongst you[/tab]\n[tab] [ch]A[/ch]\nAll you tired human beings[/tab]', { + onlyAllowTags: ['ch'] + }); + const output = [ + '[tab]', + ' ', + { + tag: 'ch', + attrs: {}, + content: ['E'], }, - content: [ - 'Foo', - ' ', - '[Bar]', - ' ' - ], - }, - ]; + '\n', + 'A', + ' ', + 'cripple', + ' ', + 'walks', + ' ', + 'amongst', + ' ', + 'you', + '[/tab]', + '\n', + '[tab]', + ' ', + { + tag: 'ch', + attrs: {}, + content: ['A'], + }, + '\n', + 'All', + ' ', + 'you', + ' ', + 'tired', + ' ', + 'human', + ' ', + 'beings', + '[/tab]', + ]; - expectOutput(ast, output); - }); + expectOutput(ast, output); + }); + }) test('parse inconsistent tags', () => { const ast = parse('[h1 name=value]Foo [Bar] /h1]'); @@ -126,32 +205,6 @@ describe('Parser', () => { 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]', - ]) - }); - test('parse few tags without spaces', () => { const ast = parse('[mytag1 size="15"]Tag1[/mytag1][mytag2 size="16"]Tag2[/mytag2][mytag3]Tag3[/mytag3]'); const output = [ @@ -189,7 +242,7 @@ describe('Parser', () => { attrs: {}, content: ['hello'], }, - ' ', + ' ', { tag: 'textarea', attrs: { diff --git a/packages/bbob-plugin-helper/src/TagNode.js b/packages/bbob-plugin-helper/src/TagNode.js index 57017cee..3c3c097c 100644 --- a/packages/bbob-plugin-helper/src/TagNode.js +++ b/packages/bbob-plugin-helper/src/TagNode.js @@ -43,22 +43,30 @@ class TagNode { return getNodeLength(this); } + toTagStart({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) { + const tagAttrs = getTagAttrs(this.tag, this.attrs); + + return `${openTag}${tagAttrs}${closeTag}`; + } + + toTagEnd({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) { + return `${openTag}${SLASH}${this.tag}${closeTag}`; + } + toTagNode() { return new TagNode(this.tag.toLowerCase(), this.attrs, this.content); } - toString() { - const OB = OPEN_BRAKET; - const CB = CLOSE_BRAKET; + toString({ openTag = OPEN_BRAKET, closeTag = 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); + const content = this.content.reduce((r, node) => r + node.toString({ openTag, closeTag }), ''); + const tagStart = this.toTagStart({ openTag, closeTag }); if (isEmpty) { - return `${OB}${tagAttrs}${CB}`; + return tagStart; } - return `${OB}${tagAttrs}${CB}${content}${OB}${SLASH}${this.tag}${CB}`; + return `${tagStart}${content}${this.toTagEnd({ openTag, closeTag })}`; } }