2
0
mirror of https://github.com/tenrok/BBob.git synced 2026-06-14 18:42:24 +03:00

fix lint error, move helper methods to char and token files

This commit is contained in:
Nikolay Kostyurin
2018-06-12 19:07:25 +02:00
parent 77ddfca271
commit a5d3fea566
13 changed files with 349 additions and 339 deletions
+3 -1
View File
@@ -7,5 +7,7 @@
"node": true, "node": true,
"jest/globals": true "jest/globals": true
}, },
"rules": {} "rules": {
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
}
} }
+5 -31
View File
@@ -1,4 +1,3 @@
function attrs(obj) { function attrs(obj) {
let attr = ''; let attr = '';
@@ -27,9 +26,7 @@ function traverse(tree, cb) {
return tree; return tree;
} }
function render(tree, options) { function render(ast) {
return html(tree);
function html(tree) { function html(tree) {
let result = ''; let result = '';
@@ -42,43 +39,20 @@ function render(tree, options) {
return; return;
} }
if (typeof node.tag === 'boolean' && !node.tag) { if (typeof node === 'object') {
typeof node.content !== 'object' && (result += node.content); result += `<${node.tag} ${attrs(node.attrs)}></${node.tag}>`;
return node.content;
} }
// treat as new root tree if node is an array // treat as new root tree if node is an array
if (Array.isArray(node)) { if (Array.isArray(node)) {
result += html(node); result += html(node);
return;
}
const tag = node.tag || 'div';
if (isSingleTag(tag, singleTags, singleRegExp)) {
result += `<${tag}${attrs(node.attrs)}`;
switch (closingSingleTag) {
case 'tag':
result += `></${tag}>`;
break;
case 'slash':
result += ' />';
break;
default:
result += '>';
}
} else {
result += `<${tag}${node.attrs ? attrs(node.attrs) : ''}>${node.content ? html(node.content) : ''}</${tag}>`;
} }
}); });
return result; return result;
} }
return html(ast);
} }
module.exports = render; module.exports = render;
+6
View File
@@ -0,0 +1,6 @@
describe('bbob-html', () => {
test('render proper markup', () => {
});
});
+14 -11
View File
@@ -10,12 +10,12 @@ const {
isTagToken, isTagToken,
isTextToken, isTextToken,
isTagEnd, isTagEnd,
} = require('./Tokenizer'); } = require('./token');
const Tokenizer = require('./Tokenizer'); const {
SLASH,
const TokenChar = Tokenizer.CHAR; getChar,
const getChar = Tokenizer.getChar; } = require('./char');
const createTagNode = (tag, attrs = {}, content = []) => ({ tag, attrs, content }); const createTagNode = (tag, attrs = {}, content = []) => ({ tag, attrs, content });
@@ -41,7 +41,7 @@ module.exports = class Parser {
const curTags = []; const curTags = [];
const curTagsAttrName = []; const curTagsAttrName = [];
const closableTags = this.findNestedTags(this.tokens); const closableTags = this.findNestedTags();
const isNestedTag = token => closableTags.indexOf(getTokenValue(token)) >= 0; const isNestedTag = token => closableTags.indexOf(getTokenValue(token)) >= 0;
@@ -123,6 +123,7 @@ module.exports = class Parser {
if (lastNestedNode) { if (lastNestedNode) {
getNodes().push(lastNestedNode); getNodes().push(lastNestedNode);
} else { } else {
// eslint-disable-next-line no-console
console.warn(`Inconsistent tag '${getTokenValue(token)}' on line ${getTokenLine(token)} and column ${getTokenColumn(token)}`); console.warn(`Inconsistent tag '${getTokenValue(token)}' on line ${getTokenLine(token)} and column ${getTokenColumn(token)}`);
} }
} }
@@ -149,14 +150,14 @@ module.exports = class Parser {
return nodes; return nodes;
} }
findNestedTags(tokens) { findNestedTags() {
const tags = tokens.filter(isTagToken).reduce((acc, token) => { const tags = this.tokens.filter(isTagToken).reduce((acc, token) => {
acc[getTokenValue(token)] = true; acc[getTokenValue(token)] = true;
return acc; return acc;
}, {}); }, {});
const closeChar = getChar(TokenChar.SLASH); const closeChar = getChar(SLASH);
return Object.keys(tags).reduce((arr, key) => { return Object.keys(tags).reduce((arr, key) => {
if (tags[key] && tags[closeChar + key]) { if (tags[key] && tags[closeChar + key]) {
@@ -168,10 +169,12 @@ module.exports = class Parser {
} }
isAllowedTag(value) { isAllowedTag(value) {
if (this.options.allowOnlyTags && this.options.allowOnlyTags.length) { if (this.options.onlyAllowTags && this.options.onlyAllowTags.length) {
return this.options.allowOnlyTags.indexOf(value) >= 0; return this.options.onlyAllowTags.indexOf(value) >= 0;
} }
return true; return true;
} }
}; };
module.exports.createTagNode = createTagNode;
+217 -263
View File
@@ -1,299 +1,253 @@
const CHAR = require('./char'); const {
getChar,
OPEN_BRAKET,
CLOSE_BRAKET, EQ, TAB, SPACE, N, QUOTEMARK,
PLACEHOLDER_SPACE, PLACEHOLDER_SPACE_TAB,
} = require('./char');
const TOKEN = require('./token'); const TOKEN = require('./token');
const getChar = String.fromCharCode;
const getTokenValue = (token) => token[Tokenizer.TOKEN.VALUE_ID];
const getTokenLine = (token) => token[Tokenizer.TOKEN.LINE_ID];
const getTokenColumn = (token) => token[Tokenizer.TOKEN.COLUMN_ID];
const isTextToken = (token) => {
const type = token[Tokenizer.TOKEN.TYPE_ID];
return type === TOKEN.TYPE_SPACE || type === TOKEN.TYPE_NEW_LINE || type === TOKEN.TYPE_WORD
};
const isTagToken = (token) => token[Tokenizer.TOKEN.TYPE_ID] === TOKEN.TYPE_TAG;
const isTagStart = (token) => !isTagEnd(token);
const isTagEnd = (token) => getTokenValue(token).charCodeAt(0) === CHAR.SLASH;
const isAttrNameToken = (token) => token[Tokenizer.TOKEN.TYPE_ID] === TOKEN.TYPE_ATTR_NAME;
const isAttrValueToken = (token) => token[Tokenizer.TOKEN.TYPE_ID] === TOKEN.TYPE_ATTR_VALUE;
const getTagName = (token) => {
const value = getTokenValue(token);
return isTagEnd(token) ? value.slice(1) : value
};
const convertTagToText = (token) => {
let text = getChar(CHAR.OPEN_BRAKET);
if (isTagEnd(token)) {
text += getChar(CHAR.SLASH)
}
text += getTokenValue(token);
text += getChar(CHAR.CLOSE_BRAKET);
return text
};
const SPACE_TAB = ' ';
const SPACE = ' ';
class Tokenizer { class Tokenizer {
constructor(input) { constructor(input) {
this.buffer = input; this.buffer = input;
this.colPos = 0; this.colPos = 0;
this.rowPos = 0; this.rowPos = 0;
this.index = 0; this.index = 0;
this.tokenIndex = -1; this.tokenIndex = -1;
this.tokens = []; this.tokens = [];
} }
appendToken(token) { appendToken(token) {
this.tokenIndex++; this.tokenIndex += 1;
this.tokens[this.tokenIndex] = token; this.tokens[this.tokenIndex] = token;
} }
tokenize() { nextCol() {
let wordToken = null; this.colPos += 1;
let tagToken = null; }
let attrNameToken = null;
let attrValueToken = null;
let attrTokens = [];
this.tokens = new Array(Math.floor(this.buffer.length / 2));
const flushWord = () => { nextLine() {
if (wordToken && wordToken[TOKEN.VALUE_ID]) { this.rowPos += 1;
this.appendToken(wordToken); }
wordToken = this.createWordToken('')
}
};
const createWord = (value, line, row) => { tokenize() {
if (!wordToken) { let wordToken = null;
wordToken = this.createWordToken(value, line, row) let tagToken = null;
} let attrNameToken = null;
}; let attrValueToken = null;
let attrTokens = [];
this.tokens = new Array(Math.floor(this.buffer.length / 2));
const flushTag = () => { const flushWord = () => {
if (tagToken !== null) { if (wordToken && wordToken[TOKEN.VALUE_ID]) {
// [] and [=] tag case this.appendToken(wordToken);
if (!tagToken[TOKEN.VALUE_ID]) { wordToken = this.createWordToken('');
const value = attrValueToken ? getChar(CHAR.EQ) : ''; }
const word = getChar(CHAR.OPEN_BRAKET) + value + getChar(CHAR.CLOSE_BRAKET); };
createWord('', 0, 0); const createWord = (value, line, row) => {
wordToken[TOKEN.VALUE_ID] += word; if (!wordToken) {
wordToken = this.createWordToken(value, line, row);
}
};
tagToken = null; const flushTag = () => {
if (tagToken !== null) {
// [] and [=] tag case
if (!tagToken[TOKEN.VALUE_ID]) {
const value = attrValueToken ? getChar(EQ) : '';
const word = getChar(OPEN_BRAKET) + value + getChar(CLOSE_BRAKET);
if (attrValueToken) { createWord('', 0, 0);
attrValueToken = null wordToken[TOKEN.VALUE_ID] += word;
}
return; tagToken = null;
}
if (attrNameToken && !attrValueToken) { if (attrValueToken) {
tagToken[TOKEN.VALUE_ID] += SPACE + attrNameToken[TOKEN.VALUE_ID]; attrValueToken = null;
attrNameToken = null }
}
this.appendToken(tagToken); return;
tagToken = null;
}
};
const flushUnclosedTag = () => {
if (tagToken !== null) {
const value = tagToken[TOKEN.VALUE_ID] + (attrValueToken ? getChar(CHAR.EQ) : '');
tagToken[TOKEN.TYPE_ID] = TOKEN.TYPE_WORD;
tagToken[TOKEN.VALUE_ID] = getChar(CHAR.OPEN_BRAKET) + value;
this.appendToken(tagToken);
tagToken = null;
if (attrValueToken) {
attrValueToken = null
}
}
};
const flushAttrNames = () => {
if (attrNameToken) {
attrTokens.push(attrNameToken);
attrNameToken = null;
}
if (attrValueToken) {
attrTokens.push(attrValueToken);
attrValueToken = null
}
};
const flushAttrs = () => {
if (attrTokens.length) {
attrTokens.forEach(this.appendToken.bind(this));
attrTokens = [];
}
};
// console.time('Lexer.tokenize');
while (this.index < this.buffer.length) {
const charCode = this.buffer.charCodeAt(this.index);
switch (charCode) {
case CHAR.TAB:
case CHAR.SPACE:
flushWord();
if (tagToken) {
attrNameToken = this.createAttrNameToken('');
} else {
const spaceCode = charCode === CHAR.TAB ? SPACE_TAB : SPACE;
this.appendToken(this.createSpaceToken(spaceCode));
}
this.colPos++;
break;
case CHAR.N:
flushWord();
this.appendToken(this.createNewLineToken(getChar(charCode)));
this.rowPos++;
this.colPos = 0;
break;
case CHAR.OPEN_BRAKET:
flushWord();
tagToken = this.createTagToken('');
this.colPos++;
break;
case CHAR.CLOSE_BRAKET:
flushTag();
flushAttrNames();
flushAttrs();
this.colPos++;
break;
case CHAR.EQ:
if (tagToken) {
attrValueToken = this.createAttrValueToken('')
} else {
wordToken[TOKEN.VALUE_ID] += getChar(charCode);
}
this.colPos++;
break;
case CHAR.QUOTEMARK:
if (attrValueToken && attrValueToken[TOKEN.VALUE_ID] > 0) {
flushAttrNames();
} else if (tagToken === null) {
wordToken[TOKEN.VALUE_ID] += getChar(charCode);
}
this.colPos++;
break;
default:
if (tagToken && attrValueToken) {
attrValueToken[TOKEN.VALUE_ID] += getChar(charCode)
} else if (tagToken && attrNameToken) {
attrNameToken[TOKEN.VALUE_ID] += getChar(charCode)
} else if (tagToken) {
tagToken[TOKEN.VALUE_ID] += getChar(charCode)
} else {
createWord();
wordToken[TOKEN.VALUE_ID] += getChar(charCode);
}
this.colPos++;
break;
}
this.index++;
} }
flushWord(); if (attrNameToken && !attrValueToken) {
flushUnclosedTag(); tagToken[TOKEN.VALUE_ID] += PLACEHOLDER_SPACE + attrNameToken[TOKEN.VALUE_ID];
attrNameToken = null;
}
this.tokens.length = this.tokenIndex + 1; this.appendToken(tagToken);
tagToken = null;
}
};
return this.tokens; const flushUnclosedTag = () => {
if (tagToken !== null) {
const value = tagToken[TOKEN.VALUE_ID] + (attrValueToken ? getChar(EQ) : '');
tagToken[TOKEN.TYPE_ID] = TOKEN.TYPE_WORD;
tagToken[TOKEN.VALUE_ID] = getChar(OPEN_BRAKET) + value;
this.appendToken(tagToken);
tagToken = null;
if (attrValueToken) {
attrValueToken = null;
}
}
};
const flushAttrNames = () => {
if (attrNameToken) {
attrTokens.push(attrNameToken);
attrNameToken = null;
}
if (attrValueToken) {
attrTokens.push(attrValueToken);
attrValueToken = null;
}
};
const flushAttrs = () => {
if (attrTokens.length) {
attrTokens.forEach(this.appendToken.bind(this));
attrTokens = [];
}
};
// console.time('Lexer.tokenize');
while (this.index < this.buffer.length) {
const charCode = this.buffer.charCodeAt(this.index);
switch (charCode) {
case TAB:
case SPACE:
flushWord();
if (tagToken) {
attrNameToken = this.createAttrNameToken('');
} else {
const spaceCode = charCode === TAB ? PLACEHOLDER_SPACE_TAB : PLACEHOLDER_SPACE;
this.appendToken(this.createSpaceToken(spaceCode));
}
this.nextCol();
break;
case N:
flushWord();
this.appendToken(this.createNewLineToken(getChar(charCode)));
this.nextLine();
this.colPos = 0;
break;
case OPEN_BRAKET:
flushWord();
tagToken = this.createTagToken('');
this.nextCol();
break;
case CLOSE_BRAKET:
flushTag();
flushAttrNames();
flushAttrs();
this.nextCol();
break;
case EQ:
if (tagToken) {
attrValueToken = this.createAttrValueToken('');
} else {
wordToken[TOKEN.VALUE_ID] += getChar(charCode);
}
this.nextCol();
break;
case QUOTEMARK:
if (attrValueToken && attrValueToken[TOKEN.VALUE_ID] > 0) {
flushAttrNames();
} else if (tagToken === null) {
wordToken[TOKEN.VALUE_ID] += getChar(charCode);
}
this.nextCol();
break;
default:
if (tagToken && attrValueToken) {
attrValueToken[TOKEN.VALUE_ID] += getChar(charCode);
} else if (tagToken && attrNameToken) {
attrNameToken[TOKEN.VALUE_ID] += getChar(charCode);
} else if (tagToken) {
tagToken[TOKEN.VALUE_ID] += getChar(charCode);
} else {
createWord();
wordToken[TOKEN.VALUE_ID] += getChar(charCode);
}
this.nextCol();
break;
}
this.index += 1;
} }
createWordToken(value = '', line = this.colPos, row = this.rowPos) { flushWord();
return [TOKEN.TYPE_WORD, value, line, row] flushUnclosedTag();
}
createTagToken(value, line = this.colPos, row = this.rowPos) { this.tokens.length = this.tokenIndex + 1;
return [TOKEN.TYPE_TAG, value, line, row]
}
createAttrNameToken(value, line = this.colPos, row = this.rowPos) { return this.tokens;
return [TOKEN.TYPE_ATTR_NAME, value, line, row] }
}
createAttrValueToken(value, line = this.colPos, row = this.rowPos) { createWordToken(value = '', line = this.colPos, row = this.rowPos) {
return [TOKEN.TYPE_ATTR_VALUE, value, line, row] return [TOKEN.TYPE_WORD, value, line, row];
} }
createSpaceToken(value, line = this.colPos, row = this.rowPos) { createTagToken(value, line = this.colPos, row = this.rowPos) {
return [TOKEN.TYPE_SPACE, value, line, row] return [TOKEN.TYPE_TAG, value, line, row];
} }
createNewLineToken(value, line = this.colPos, row = this.rowPos) { createAttrNameToken(value, line = this.colPos, row = this.rowPos) {
return [TOKEN.TYPE_NEW_LINE, value, line, row] return [TOKEN.TYPE_ATTR_NAME, value, line, row];
} }
createAttrValueToken(value, line = this.colPos, row = this.rowPos) {
return [TOKEN.TYPE_ATTR_VALUE, value, line, row];
}
createSpaceToken(value, line = this.colPos, row = this.rowPos) {
return [TOKEN.TYPE_SPACE, value, line, row];
}
createNewLineToken(value, line = this.colPos, row = this.rowPos) {
return [TOKEN.TYPE_NEW_LINE, value, line, row];
}
} }
// warm up tokenizer to elimitate code branches that never execute // warm up tokenizer to elimitate code branches that never execute
new Tokenizer(`[sc=asdasd`).tokenize(); new Tokenizer('[b param="hello"]Sample text[/b]\n\t[Chorus 2]').tokenize();
//new Tokenizer(`[b param="hello"]Sample text[/b]\n\t[Chorus]`).tokenize();
module.exports = Tokenizer; module.exports = Tokenizer;
module.exports.CHAR = CHAR;
module.exports.TYPE = { module.exports.TYPE = {
WORD: TOKEN.TYPE_WORD, WORD: TOKEN.TYPE_WORD,
TAG: TOKEN.TYPE_TAG, TAG: TOKEN.TYPE_TAG,
ATTR_NAME: TOKEN.TYPE_ATTR_NAME, ATTR_NAME: TOKEN.TYPE_ATTR_NAME,
ATTR_VALUE: TOKEN.TYPE_ATTR_VALUE, ATTR_VALUE: TOKEN.TYPE_ATTR_VALUE,
SPACE: TOKEN.TYPE_SPACE, SPACE: TOKEN.TYPE_SPACE,
NEW_LINE: TOKEN.TYPE_NEW_LINE, NEW_LINE: TOKEN.TYPE_NEW_LINE,
}; };
module.exports.TOKEN = { module.exports.TOKEN = {
TYPE_ID: TOKEN.TYPE_ID, TYPE_ID: TOKEN.TYPE_ID,
VALUE_ID: TOKEN.VALUE_ID, VALUE_ID: TOKEN.VALUE_ID,
LINE_ID: TOKEN.LINE_ID, LINE_ID: TOKEN.LINE_ID,
COLUMN_ID: TOKEN.COLUMN_ID, COLUMN_ID: TOKEN.COLUMN_ID,
}; };
module.exports.getChar = getChar;
module.exports.getTokenValue = getTokenValue;
module.exports.getTokenLine = getTokenLine;
module.exports.getTokenColumn = getTokenColumn;
module.exports.isTextToken = isTextToken;
module.exports.isTagToken = isTagToken;
module.exports.isTagStart = isTagStart;
module.exports.isTagEnd = isTagEnd;
module.exports.isAttrNameToken = isAttrNameToken;
module.exports.isAttrValueToken = isAttrValueToken;
module.exports.getTagName = getTagName;
module.exports.convertTokenToText = convertTagToText;
+1 -1
View File
@@ -1,6 +1,6 @@
const Tokenizer = require('./Tokenizer'); const Tokenizer = require('./Tokenizer');
const TYPE = Tokenizer.TYPE; const { TYPE } = Tokenizer;
const tokenize = input => (new Tokenizer(input).tokenize()); const tokenize = input => (new Tokenizer(input).tokenize());
+8
View File
@@ -12,7 +12,13 @@ const CLOSE_BRAKET = ']'.charCodeAt(0);
const SLASH = '/'.charCodeAt(0); const SLASH = '/'.charCodeAt(0);
const PLACEHOLDER_SPACE_TAB = ' ';
const PLACEHOLDER_SPACE = ' ';
const getChar = String.fromCharCode;
module.exports = { module.exports = {
getChar,
N, N,
F, F,
R, R,
@@ -23,4 +29,6 @@ module.exports = {
OPEN_BRAKET, OPEN_BRAKET,
CLOSE_BRAKET, CLOSE_BRAKET,
SLASH, SLASH,
PLACEHOLDER_SPACE_TAB,
PLACEHOLDER_SPACE,
}; };
+1 -1
View File
@@ -1 +1 @@
module.exports = require('./parse'); module.exports = require('./parse');
-4
View File
@@ -1,9 +1,5 @@
const parse = require('./index'); const parse = require('./index');
const options = {
allowOnlyTags: ['ch', 'syllable', 'tab'],
};
describe('parse', () => { describe('parse', () => {
test('tag with spaces', () => { test('tag with spaces', () => {
const ast = parse('[Verse 2]'); const ast = parse('[Verse 2]');
+56 -1
View File
@@ -1,3 +1,10 @@
const {
getChar,
OPEN_BRAKET,
CLOSE_BRAKET,
SLASH,
} = require('./char');
const TOKEN_TYPE_ID = 0; const TOKEN_TYPE_ID = 0;
const TOKEN_VALUE_ID = 1; const TOKEN_VALUE_ID = 1;
const TOKEN_COLUMN_ID = 2; const TOKEN_COLUMN_ID = 2;
@@ -10,6 +17,43 @@ const TOKEN_TYPE_ATTR_VALUE = 'attr-value';
const TOKEN_TYPE_SPACE = 'space'; const TOKEN_TYPE_SPACE = 'space';
const TOKEN_TYPE_NEW_LINE = 'new-line'; const TOKEN_TYPE_NEW_LINE = 'new-line';
const getTokenValue = token => token[TOKEN_VALUE_ID];
const getTokenLine = token => token[TOKEN_LINE_ID];
const getTokenColumn = token => token[TOKEN_COLUMN_ID];
const isTextToken = (token) => {
const type = token[TOKEN_TYPE_ID];
return type === TOKEN_TYPE_SPACE || type === TOKEN_TYPE_NEW_LINE || type === TOKEN_TYPE_WORD;
};
const isTagToken = token => token[TOKEN_TYPE_ID] === TOKEN_TYPE_TAG;
const isTagEnd = token => getTokenValue(token).charCodeAt(0) === SLASH;
const isTagStart = token => !isTagEnd(token);
const isAttrNameToken = token => token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_NAME;
const isAttrValueToken = token => token[TOKEN_TYPE_ID] === TOKEN_TYPE_ATTR_VALUE;
const getTagName = (token) => {
const value = getTokenValue(token);
return isTagEnd(token) ? value.slice(1) : value;
};
const convertTagToText = (token) => {
let text = getChar(OPEN_BRAKET);
if (isTagEnd(token)) {
text += getChar(SLASH);
}
text += getTokenValue(token);
text += getChar(CLOSE_BRAKET);
return text;
};
module.exports = { module.exports = {
TYPE_ID: TOKEN_TYPE_ID, TYPE_ID: TOKEN_TYPE_ID,
VALUE_ID: TOKEN_VALUE_ID, VALUE_ID: TOKEN_VALUE_ID,
@@ -20,5 +64,16 @@ module.exports = {
TYPE_ATTR_NAME: TOKEN_TYPE_ATTR_NAME, TYPE_ATTR_NAME: TOKEN_TYPE_ATTR_NAME,
TYPE_ATTR_VALUE: TOKEN_TYPE_ATTR_VALUE, TYPE_ATTR_VALUE: TOKEN_TYPE_ATTR_VALUE,
TYPE_SPACE: TOKEN_TYPE_SPACE, TYPE_SPACE: TOKEN_TYPE_SPACE,
TYPE_NEW_LINE: TOKEN_TYPE_NEW_LINE TYPE_NEW_LINE: TOKEN_TYPE_NEW_LINE,
convertTagToText,
getTagName,
getTokenColumn,
getTokenLine,
getTokenValue,
isAttrNameToken,
isAttrValueToken,
isTagStart,
isTagToken,
isTextToken,
isTagEnd,
}; };
+29 -23
View File
@@ -1,41 +1,47 @@
const React = require('react'); const React = require('react');
const parse = require('bbob-html'); const PropTypes = require('prop-types');
const parse = require('@bbob/html');
class BBCode extends React.Component { class BBCode extends React.Component {
render() {
const Container = this.props.container;
return (
<Container>
{this.content()}
</Container>
);
}
content() { content() {
if (this.props.source) { if (this.props.source) {
// eslint-disable-next-line react/no-danger
return <span dangerouslySetInnerHTML={{ __html: this.renderBBCode(this.props.source) }} />; return <span dangerouslySetInnerHTML={{ __html: this.renderBBCode(this.props.source) }} />;
} }
else {
return React.Children.map(this.props.children, child => { return React.Children.map(this.props.children, (child) => {
if (typeof child === 'string') { if (typeof child === 'string') {
return <span dangerouslySetInnerHTML={{ __html: this.renderBBCode(child) }} />; // eslint-disable-next-line react/no-danger
} return <span dangerouslySetInnerHTML={{ __html: this.renderBBCode(child) }} />;
else { }
return child; return child;
} });
});
}
} }
renderBBCode(source) { renderBBCode(source) {
return parse(source) return parse(source, this.props.options);
}
render() {
const Container = this.props.container;
return (<Container>{this.content()}</Container>);
} }
} }
BBCode.propTypes = {
container: PropTypes.node,
children: PropTypes.element.isRequired,
source: PropTypes.string,
options: PropTypes.shape({
prop: PropTypes.bool,
}),
};
BBCode.defaultProps = { BBCode.defaultProps = {
container: 'div', container: 'div',
options: {}, options: {},
source: null,
}; };
module.exports = BBCode; module.exports = BBCode;
+1 -3
View File
@@ -1,7 +1,5 @@
describe('React BBCode', () => { describe('React BBCode', () => {
test('render markup properly', () => { test('render markup properly', () => {
}) });
}); });
+8
View File
@@ -12,5 +12,13 @@
"license": "MIT", "license": "MIT",
"publishConfig": { "publishConfig": {
"registry": "https://registry.npmjs.org/" "registry": "https://registry.npmjs.org/"
},
"dependencies": {
"@bbob/html": "^1.0.1",
"prop-types": "^15.6.1",
"react": "^15.6.2"
},
"peerDependencies": {
"react": "15.x"
} }
} }