2
0
mirror of https://github.com/tenrok/BBob.git synced 2026-05-15 11:59:37 +03:00

add eslint, travis config, test tasks

This commit is contained in:
Nikolay Kostyurin
2018-06-11 22:31:02 +02:00
parent 305643daa2
commit 792e949b6e
36 changed files with 6529 additions and 434 deletions
+28
View File
@@ -0,0 +1,28 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8
# Tab indentation (no size specified)
[Makefile]
indent_style = tab
# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2
+11
View File
@@ -0,0 +1,11 @@
{
"extends": "airbnb",
"plugins": [
"jest"
],
"env": {
"node": true,
"jest/globals": true
},
"rules": {}
}
+1
View File
@@ -59,3 +59,4 @@ typings/
# next.js build output
.next
.idea
+16
View File
@@ -0,0 +1,16 @@
language: node_js
node_js:
- 'lts/*'
script:
- 'npm run bootstrap'
- 'set -e'
- 'npm run lint'
- 'npm run test'
after_success:
- 'npm run cover'
notifications:
email: false
@@ -1,4 +1,4 @@
const parse = require('../index');
const parse = require('../packages/bbob-parser/index');
const options = {
closableTags: ['ch', 'syllable', 'tab']
+1 -1
View File
@@ -1,7 +1,7 @@
{
"lerna": "2.11.0",
"packages": [
"packages/bbob-parser"
"packages/*"
],
"version": "independent"
}
+5912 -73
View File
File diff suppressed because it is too large Load Diff
+22 -3
View File
@@ -1,5 +1,24 @@
{
"devDependencies": {
"lerna": "^2.11.0"
}
"scripts": {
"bootstrap": "lerna bootstrap",
"test": "lerna run test",
"cover": "lerna run cover",
"lint": "lerna run lint"
},
"author": {
"name": "Nikolay Kostyurin",
"url": "https://artkost.ru/"
},
"license": "MIT",
"devDependencies": {
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-jest": "^21.17.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.9.1",
"jest": "^23.1.0",
"lerna": "^2.11.0",
"xbbcode-parser": "^0.1.2"
}
}
+3
View File
@@ -0,0 +1,3 @@
package-lock.json
coverage
dist
+5
View File
@@ -0,0 +1,5 @@
package-lock.json
coverage
src
dist
!lib
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/env node
require('../lib/cli');
+24
View File
@@ -0,0 +1,24 @@
'use strict';
const fs = require('fs');
const program = require('commander');
const version = require('../package.json').version;
program
.version(version)
.parse(process.argv);
function readFile(filename, encoding, callback) {
if (options.file === '-') {
// read from stdin
const chunks = [];
process.stdin.on('data', function (chunk) { chunks.push(chunk); });
process.stdin.on('end', function () {
return callback(null, Buffer.concat(chunks).toString(encoding));
});
} else {
fs.readFile(filename, encoding, callback);
}
}
+8
View File
@@ -0,0 +1,8 @@
describe('CLI Interface', () => {
test('read from file', () => {
})
});
+26
View File
@@ -0,0 +1,26 @@
{
"name": "@bbob/cli",
"version": "1.0.0",
"description": "Comand line bbcode parser",
"main": "lib/bbob.js",
"bin": {
"cli": "bbob.js"
},
"scripts": {
"test": "../../node_modules/.bin/jest --",
"cover": "../../node_modules/.bin/jest --coverage"
},
"author": "Nikolay Kostyurin <jilizart@gmail.com>",
"license": "MIT",
"directories": {
"lib": "lib"
},
"dependencies": {
"@bbob/parser": "^1.0.0",
"commander": "^2.15.1"
},
"devDependencies": {
"jest": "^23.1.0",
"xbbcode-parser": "^0.1.2"
}
}
+3
View File
@@ -0,0 +1,3 @@
package-lock.json
coverage
dist
+5
View File
@@ -0,0 +1,5 @@
package-lock.json
coverage
src
dist
!lib
+2
View File
@@ -0,0 +1,2 @@
# bbob-render
Converts bbob-parser AST tree to html
+35
View File
@@ -0,0 +1,35 @@
function render(tree, options) {
}
function attrs(obj) {
let attr = '';
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === 'boolean' && obj[key]) {
attr += ` ${key}`;
} else if (typeof obj[key] === 'number') {
attr += ` ${key}="${obj[key]}"`;
} else if (typeof obj[key] === 'string') {
attr += ` ${key}="${obj[key].replace(/"/g, '&quot;')}"`;
}
});
return attr;
}
function traverse(tree, cb) {
if (Array.isArray(tree)) {
let i = 0,
length = tree.length;
for (; i < length; i++) {
traverse(cb(tree[i]), cb);
}
} else if (typeof tree === 'object' && tree.hasOwnProperty('content')) {
traverse(tree.content, cb);
}
return tree;
}
module.exports = render;
View File
-1
View File
@@ -1,4 +1,3 @@
package-lock.json
coverage
lib
dist
+5 -2
View File
@@ -1,2 +1,5 @@
benchmark
*.test.js
package-lock.json
coverage
src
dist
!lib
+155 -152
View File
@@ -1,174 +1,177 @@
const {
convertTokenToText,
getTagName,
getTokenColumn,
getTokenLine,
getTokenValue,
isAttrNameToken,
isAttrValueToken,
isTagStart,
isTagToken,
isTextToken,
isTagEnd
} = require("./Tokenizer");
const Tokenizer = require("./Tokenizer");
convertTokenToText,
getTagName,
getTokenColumn,
getTokenLine,
getTokenValue,
isAttrNameToken,
isAttrValueToken,
isTagStart,
isTagToken,
isTextToken,
isTagEnd,
} = require('./Tokenizer');
const Tokenizer = require('./Tokenizer');
const TokenChar = Tokenizer.CHAR;
const getChar = Tokenizer.getChar;
const createTagNode = (name, attrs = {}, content = []) => ({tag: name, attrs, content});
const createTagNode = (name, attrs = {}, content = []) => ({ tag: name, attrs, content });
/**
*
{
tag: 'div',
attrs: {
class: 'foo'
},
content: ['hello world!']
}
{
tag: 'div',
attrs: {
class: 'foo'
},
content: ['hello world!']
}
*/
module.exports = class Parser {
constructor(tokens, options = {}) {
this.tokens = tokens;
this.options = options
}
constructor(tokens, options = {}) {
this.tokens = tokens;
this.options = options;
}
parse() {
const tokens = this.tokens;
const nodes = [];
const nestedNodes = [];
const curTags = [];
const curTagsAttrName = [];
parse() {
const nodes = [];
const nestedNodes = [];
const curTags = [];
const curTagsAttrName = [];
const closableTags = this.findNestedTags(tokens);
const closableTags = this.findNestedTags(this.tokens);
const isNestedTag = (token) => closableTags.indexOf(getTokenValue(token)) >= 0;
const isNestedTag = token => closableTags.indexOf(getTokenValue(token)) >= 0;
const getCurTag = () => {
if (curTags.length) {
return curTags[curTags.length - 1]
const getCurTag = () => {
if (curTags.length) {
return curTags[curTags.length - 1];
}
return null;
};
const createCurTag = (token) => {
curTags.push(createTagNode(getTokenValue(token)));
};
const getCurTagAttrName = () => {
if (curTagsAttrName.length) {
return curTagsAttrName[curTagsAttrName.length - 1];
}
return null;
};
const createCurTagAttrName = (token) => {
curTagsAttrName.push(getTokenValue(token));
};
const clearCurTagAttrName = () => {
if (curTagsAttrName.length) {
curTagsAttrName.pop();
}
};
const clearCurTag = () => {
if (curTags.length) {
curTags.pop();
clearCurTagAttrName();
}
};
const getNodes = () => {
if (nestedNodes.length) {
const nestedNode = nestedNodes[nestedNodes.length - 1];
return nestedNode.content;
}
return nodes;
};
let token;
// eslint-disable-next-line no-cond-assign
while (token = this.tokens.shift()) {
if (!token) {
// eslint-disable-next-line no-continue
continue;
}
if (isTagToken(token)) {
if (this.isAllowedTag(getTagName(token))) {
// [tag]
if (isTagStart(token)) {
createCurTag(token);
if (isNestedTag(token)) {
nestedNodes.push(getCurTag());
} else {
getNodes().push(getCurTag());
clearCurTag();
}
}
return null
};
// [/tag]
if (isTagEnd(token)) {
clearCurTag();
const createCurTag = (token) => {
curTags.push(createTagNode(getTokenValue(token)))
};
const lastNestedNode = nestedNodes.pop();
const clearCurTag = () => {
if (curTags.length) {
curTags.pop();
clearCurTagAttrName()
}
};
const getCurTagAttrName = () => {
if (curTagsAttrName.length) {
return curTagsAttrName[curTagsAttrName.length - 1]
}
return null
};
const createCurTagAttrName = (token) => {
curTagsAttrName.push(getTokenValue(token))
};
const clearCurTagAttrName = () => {
if (curTagsAttrName.length) {
curTagsAttrName.pop()
}
};
const getNodes = () => {
if (nestedNodes.length) {
const nestedNode = nestedNodes[nestedNodes.length - 1];
return nestedNode.content
}
return nodes
};
let token;
while (token = tokens.shift()) {
if (!token) {
continue;
}
if (isTagToken(token)) {
if (this.isAllowedTag(getTagName(token))) {
// [tag]
if (isTagStart(token)) {
createCurTag(token);
if (isNestedTag(token)) {
nestedNodes.push(getCurTag())
} else {
getNodes().push(getCurTag());
clearCurTag()
}
}
// [/tag]
if (isTagEnd(token)) {
clearCurTag();
const lastNestedNode = nestedNodes.pop();
if (lastNestedNode) {
getNodes().push(lastNestedNode)
} else {
console.warn(`Inconsistent tag '${getTokenValue(token)}' on line ${getTokenLine(token)} and column ${getTokenColumn(token)}`);
}
}
} else {
getNodes().push(convertTokenToText(token))
}
}
if (getCurTag()) {
if (isAttrNameToken(token)) {
createCurTagAttrName(token);
getCurTag().attrs[getCurTagAttrName()] = null
} else if (isAttrValueToken(token)) {
getCurTag().attrs[getCurTagAttrName()] = getTokenValue(token);
clearCurTagAttrName()
} else if (isTextToken(token)) {
getCurTag().content.push(getTokenValue(token))
}
} else if (isTextToken(token)) {
getNodes().push(getTokenValue(token))
if (lastNestedNode) {
getNodes().push(lastNestedNode);
} else {
console.warn(`Inconsistent tag '${getTokenValue(token)}' on line ${getTokenLine(token)} and column ${getTokenColumn(token)}`);
}
}
} else {
getNodes().push(convertTokenToText(token));
}
}
return nodes
}
findNestedTags(tokens) {
const tags = tokens.filter(isTagToken).reduce((acc, token) => {
acc[getTokenValue(token)] = true;
return acc
}, {});
const closeChar = getChar(TokenChar.SLASH);
return Object.keys(tags).reduce((arr, key) => {
if (tags[key] && tags[closeChar + key]) {
arr.push(key)
}
return arr;
}, [])
}
isAllowedTag(value) {
if (this.options.allowOnlyTags && this.options.allowOnlyTags.length) {
return this.options.allowOnlyTags.indexOf(value) >= 0
if (getCurTag()) {
if (isAttrNameToken(token)) {
createCurTagAttrName(token);
getCurTag().attrs[getCurTagAttrName()] = null;
} else if (isAttrValueToken(token)) {
getCurTag().attrs[getCurTagAttrName()] = getTokenValue(token);
clearCurTagAttrName();
} else if (isTextToken(token)) {
getCurTag().content.push(getTokenValue(token));
}
return true
} else if (isTextToken(token)) {
getNodes().push(getTokenValue(token));
}
}
};
return nodes;
}
findNestedTags(tokens) {
const tags = tokens.filter(isTagToken).reduce((acc, token) => {
acc[getTokenValue(token)] = true;
return acc;
}, {});
const closeChar = getChar(TokenChar.SLASH);
return Object.keys(tags).reduce((arr, key) => {
if (tags[key] && tags[closeChar + key]) {
arr.push(key);
}
return arr;
}, []);
}
isAllowedTag(value) {
if (this.options.allowOnlyTags && this.options.allowOnlyTags.length) {
return this.options.allowOnlyTags.indexOf(value) >= 0;
}
return true;
}
};
+8 -9
View File
@@ -1,12 +1,11 @@
const Parser = require('./Parser');
const TOKEN = require('./token');
describe("Parser", () => {
test("parse paired tags tokens", () => {
const parser = new Parser([
[TOKEN.TYPE_TAG, 'ch'],
[TOKEN.TYPE_TAG, '/ch']
]);
})
});
describe('Parser', () => {
test('parse paired tags tokens', () => {
const parser = new Parser([
[TOKEN.TYPE_TAG, 'ch'],
[TOKEN.TYPE_TAG, '/ch'],
]);
});
});
+1 -1
View File
@@ -52,7 +52,7 @@ class Tokenizer {
this.colPos = 0;
this.rowPos = 0;
this.index = 0;
this.tokenIndex = -1;
this.tokens = [];
}
+127 -126
View File
@@ -1,144 +1,145 @@
const Tokenizer = require('./Tokenizer');
const TYPE = Tokenizer.TYPE;
describe("Tokenizer", () => {
test("tokenize single tag", () => {
const input = `[SingleTag]`;
const tokens = new Tokenizer(input).tokenize();
describe('Tokenizer', () => {
test('tokenize single tag', () => {
const input = '[SingleTag]';
const tokens = new Tokenizer(input).tokenize();
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'SingleTag', 0, 0]
])
});
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'SingleTag', 0, 0],
]);
});
test("tokenize single tag with spaces", () => {
const input = `[Single Tag]`;
const tokens = new Tokenizer(input).tokenize();
test('tokenize single tag with spaces', () => {
const input = '[Single Tag]';
const tokens = new Tokenizer(input).tokenize();
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'Single Tag', 0, 0]
])
});
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'Single Tag', 0, 0],
]);
});
test("tokenize tag as param", () => {
const input = `[color="#ff0000"]Text[/color]`;
const tokens = new Tokenizer(input).tokenize();
test('tokenize tag as param', () => {
const input = '[color="#ff0000"]Text[/color]';
const tokens = new Tokenizer(input).tokenize();
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'color', 0, 0],
[TYPE.ATTR_VALUE, '#ff0000', 6, 0],
[TYPE.WORD, 'Text', 17, 0],
[TYPE.TAG, '/color', 21, 0]
])
});
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'color', 0, 0],
[TYPE.ATTR_VALUE, '#ff0000', 6, 0],
[TYPE.WORD, 'Text', 17, 0],
[TYPE.TAG, '/color', 21, 0],
]);
});
test("tokenize tag param without quotemarks", () => {
const input = `[style color=#ff0000]Text[/style]`;
const tokens = new Tokenizer(input).tokenize();
test('tokenize tag param without quotemarks', () => {
const input = '[style color=#ff0000]Text[/style]';
const tokens = new Tokenizer(input).tokenize();
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'style', 0, 0],
[TYPE.ATTR_NAME, 'color', 6, 0],
[TYPE.ATTR_VALUE, '#ff0000', 12, 0],
[TYPE.WORD, 'Text', 21, 0],
[TYPE.TAG, '/style', 25, 0]
])
});
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'style', 0, 0],
[TYPE.ATTR_NAME, 'color', 6, 0],
[TYPE.ATTR_VALUE, '#ff0000', 12, 0],
[TYPE.WORD, 'Text', 21, 0],
[TYPE.TAG, '/style', 25, 0],
]);
});
test("tokenize list tag with items", () => {
const input = `[list]
test('tokenize list tag with items', () => {
const input = `[list]
[*] Item 1.
[*] Item 2.
[*] Item 3.
[/list]`;
const tokens = new Tokenizer(input).tokenize();
const tokens = new Tokenizer(input).tokenize();
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'list', 0, 0],
[TYPE.NEW_LINE, '\n', 6, 0],
[TYPE.SPACE, ' ', 0, 1],
[TYPE.SPACE, ' ', 1, 1],
[TYPE.SPACE, ' ', 2, 1],
[TYPE.TAG, '*', 3, 1],
[TYPE.SPACE, ' ', 6, 1],
[TYPE.WORD, 'Item', 7, 1],
[TYPE.SPACE, ' ', 11, 1],
[TYPE.WORD, '1.', 11, 1],
[TYPE.NEW_LINE, '\n', 14, 1],
[TYPE.SPACE, ' ', 0, 2],
[TYPE.SPACE, ' ', 1, 2],
[TYPE.SPACE, ' ', 2, 2],
[TYPE.TAG, '*', 3, 2],
[TYPE.SPACE, ' ', 6, 2],
[TYPE.WORD, 'Item', 14, 1],
[TYPE.SPACE, ' ', 11, 2],
[TYPE.WORD, '2.', 11, 2],
[TYPE.NEW_LINE, '\n', 14, 2],
[TYPE.SPACE, ' ', 0, 3],
[TYPE.SPACE, ' ', 1, 3],
[TYPE.SPACE, ' ', 2, 3],
[TYPE.TAG, '*', 3, 3],
[TYPE.SPACE, ' ', 6, 3],
[TYPE.WORD, 'Item', 14, 2],
[TYPE.SPACE, ' ', 11, 3],
[TYPE.WORD, '3.', 11, 3],
[TYPE.NEW_LINE, '\n', 14, 3],
[TYPE.TAG, '/list', 0, 4]
])
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual([
[TYPE.TAG, 'list', 0, 0],
[TYPE.NEW_LINE, '\n', 6, 0],
[TYPE.SPACE, ' ', 0, 1],
[TYPE.SPACE, ' ', 1, 1],
[TYPE.SPACE, ' ', 2, 1],
[TYPE.TAG, '*', 3, 1],
[TYPE.SPACE, ' ', 6, 1],
[TYPE.WORD, 'Item', 7, 1],
[TYPE.SPACE, ' ', 11, 1],
[TYPE.WORD, '1.', 11, 1],
[TYPE.NEW_LINE, '\n', 14, 1],
[TYPE.SPACE, ' ', 0, 2],
[TYPE.SPACE, ' ', 1, 2],
[TYPE.SPACE, ' ', 2, 2],
[TYPE.TAG, '*', 3, 2],
[TYPE.SPACE, ' ', 6, 2],
[TYPE.WORD, 'Item', 14, 1],
[TYPE.SPACE, ' ', 11, 2],
[TYPE.WORD, '2.', 11, 2],
[TYPE.NEW_LINE, '\n', 14, 2],
[TYPE.SPACE, ' ', 0, 3],
[TYPE.SPACE, ' ', 1, 3],
[TYPE.SPACE, ' ', 2, 3],
[TYPE.TAG, '*', 3, 3],
[TYPE.SPACE, ' ', 6, 3],
[TYPE.WORD, 'Item', 14, 2],
[TYPE.SPACE, ' ', 11, 3],
[TYPE.WORD, '3.', 11, 3],
[TYPE.NEW_LINE, '\n', 14, 3],
[TYPE.TAG, '/list', 0, 4],
]);
});
test('tokenize bad tags as texts', () => {
const inputs = [
'[]',
'[=]',
'![](image.jpg)',
'x html([a. title][, alt][, classes]) x',
'[/y]',
'[sc',
// '[sc / [/sc]',
// '[sc arg="val',
];
const asserts = [
[[TYPE.WORD, '[]', 0, 0]],
[[TYPE.WORD, '[=]', 0, 0]],
[
[TYPE.WORD, '!', 0, 0],
[TYPE.WORD, '[](image.jpg)', 1, 0],
],
[
[TYPE.WORD, 'x', 0, 0],
[TYPE.SPACE, ' ', 1, 0],
[TYPE.WORD, 'html(', 1, 0],
[TYPE.TAG, 'a. title', 7, 0],
[TYPE.TAG, ', alt', 17, 0],
[TYPE.TAG, ', classes', 24, 0],
[TYPE.WORD, ')', 7, 0],
[TYPE.SPACE, ' ', 36, 0],
[TYPE.WORD, 'x', 36, 0],
],
[[TYPE.TAG, '/y', 0, 0]],
[[TYPE.WORD, '[sc', 0, 0]],
[
[TYPE.WORD, '[sc', 0, 0],
[TYPE.SPACE, ' ', 0, 0],
[TYPE.WORD, '/', 0, 0],
[TYPE.SPACE, ' ', 0, 0],
[TYPE.WORD, '[/sc]', 0, 0],
],
];
inputs.forEach((input, idx) => {
const tokens = new Tokenizer(input).tokenize();
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual(asserts[idx]);
});
test("tokenize bad tags as texts", () => {
const inputs = [
'[]',
'[=]',
'![](image.jpg)',
'x html([a. title][, alt][, classes]) x',
'[/y]',
'[sc',
'[sc / [/sc]',
'[sc arg="val',
];
const asserts = [
[[TYPE.WORD, '[]', 0, 0]],
[[TYPE.WORD, '[=]', 0, 0]],
[
[TYPE.WORD, '!', 0, 0],
[TYPE.WORD, '[](image.jpg)', 1, 0]
],
[
[TYPE.WORD, "x", 0, 0],
[TYPE.SPACE, " ", 1, 0],
[TYPE.WORD, "html(", 1, 0],
[TYPE.TAG, "a. title", 7, 0],
[TYPE.TAG, ", alt", 17, 0],
[TYPE.TAG, ", classes", 24, 0],
[TYPE.WORD, ")", 7, 0],
[TYPE.SPACE, " ", 36, 0],
[TYPE.WORD, "x", 36, 0]
],
[[TYPE.TAG, "/y", 0, 0]],
[[TYPE.WORD, '[sc', 0, 0]],
[
[TYPE.WORD, '[sc', 0, 0],
[TYPE.SPACE, ' ', 0, 0],
[TYPE.WORD, '/', 0, 0],
[TYPE.SPACE, ' ', 0, 0],
[TYPE.WORD, '[/sc]', 0, 0]
],
];
inputs.forEach((input, idx) => {
const tokens = new Tokenizer(input).tokenize();
expect(tokens).toBeInstanceOf(Array);
expect(tokens).toEqual(asserts[idx])
});
})
});
});
});
+21 -21
View File
@@ -1,26 +1,26 @@
const N = "\n".charCodeAt(0);
const TAB = "\t".charCodeAt(0);
const F = "\f".charCodeAt(0);
const R = "\r".charCodeAt(0);
const N = '\n'.charCodeAt(0);
const TAB = '\t'.charCodeAt(0);
const F = '\f'.charCodeAt(0);
const R = '\r'.charCodeAt(0);
const EQ = "=".charCodeAt(0);
const QUOTEMARK = "\"".charCodeAt(0);
const SPACE = " ".charCodeAt(0);
const EQ = '='.charCodeAt(0);
const QUOTEMARK = '"'.charCodeAt(0);
const SPACE = ' '.charCodeAt(0);
const OPEN_BRAKET = "[".charCodeAt(0);
const CLOSE_BRAKET = "]".charCodeAt(0);
const OPEN_BRAKET = '['.charCodeAt(0);
const CLOSE_BRAKET = ']'.charCodeAt(0);
const SLASH = "/".charCodeAt(0);
const SLASH = '/'.charCodeAt(0);
module.exports = {
N,
F,
R,
TAB,
EQ,
QUOTEMARK,
SPACE,
OPEN_BRAKET,
CLOSE_BRAKET,
SLASH
};
N,
F,
R,
TAB,
EQ,
QUOTEMARK,
SPACE,
OPEN_BRAKET,
CLOSE_BRAKET,
SLASH,
};
+4 -6
View File
@@ -1,5 +1,5 @@
{
"name": "bbob-parser",
"name": "@bbob/parser",
"version": "1.0.1",
"description": "Fast BB Code parser written in pure javascript, no dependencies",
"main": "index.js",
@@ -7,14 +7,12 @@
"test": "test"
},
"scripts": {
"test": "jest"
"test": "../../node_modules/.bin/jest --",
"cover": "../../node_modules/.bin/jest --coverage",
"lint": "../../node_modules/.bin/eslint ."
},
"author": "Nikolay Kostyurin <jilizart@gmail.com>",
"license": "MIT",
"devDependencies": {
"jest": "^23.1.0",
"xbbcode-parser": "^0.1.2"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
}
+8 -8
View File
@@ -1,11 +1,11 @@
const Tokenizer = require("./Tokenizer");
const Parser = require("./Parser");
const Tokenizer = require('./Tokenizer');
const Parser = require('./Parser');
module.exports = function parse(input, options) {
const tokenizer = new Tokenizer(input);
const tokens = tokenizer.tokenize();
const parser = new Parser(tokens, options);
const ast = parser.parse();
const tokenizer = new Tokenizer(input);
const tokens = tokenizer.tokenize();
const parser = new Parser(tokens, options);
const ast = parser.parse();
return ast
};
return ast;
};
+30 -30
View File
@@ -1,37 +1,37 @@
const parse = require('./index');
const options = {
allowOnlyTags: ['ch', 'syllable', 'tab'],
allowOnlyTags: ['ch', 'syllable', 'tab'],
};
describe("parse", () => {
test("tag with spaces", () => {
const ast = parse(`[Verse 2]`);
describe('parse', () => {
test('tag with spaces', () => {
const ast = parse('[Verse 2]');
expect(ast).toEqual([{tag: 'Verse 2', attrs: {}, content: []}]);
});
expect(ast).toEqual([{ tag: 'Verse 2', attrs: {}, content: [] }]);
});
// test("pass invalid tags", () => {
// const inputs = [
// '[]',
// '![](image.jpg)',
// 'x html([a. title][, alt][, classes]) x',
// '[/y]',
// '[sc',
// '[sc / [/sc]',
// '[sc arg="val',
// ];
//
// const ast1 = parse(inputs[0]);
//
//
//
// console.log('ast1', ast1);
//
//
//
// expect(ast1).toEqual([
//
// ]);
// })
});
// test("pass invalid tags", () => {
// const inputs = [
// '[]',
// '![](image.jpg)',
// 'x html([a. title][, alt][, classes]) x',
// '[/y]',
// '[sc',
// '[sc / [/sc]',
// '[sc arg="val',
// ];
//
// const ast1 = parse(inputs[0]);
//
//
//
// console.log('ast1', ast1);
//
//
//
// expect(ast1).toEqual([
//
// ]);
// })
});
+41
View File
@@ -0,0 +1,41 @@
const React = require('react');
const parse = require('bbob-html');
class BBCode extends React.Component {
render() {
const Container = this.props.container;
return (
<Container>
{this.content()}
</Container>
);
}
content() {
if (this.props.source) {
return <span dangerouslySetInnerHTML={{ __html: this.renderBBCode(this.props.source) }} />;
}
else {
return React.Children.map(this.props.children, child => {
if (typeof child === 'string') {
return <span dangerouslySetInnerHTML={{ __html: this.renderBBCode(child) }} />;
}
else {
return child;
}
});
}
}
renderBBCode(source) {
return parse(source)
}
}
BBCode.defaultProps = {
container: 'div',
options: {},
};
module.exports = BBCode;
+7
View File
@@ -0,0 +1,7 @@
describe('React BBCode', () => {
test('render markup properly', () => {
})
});
+13
View File
@@ -0,0 +1,13 @@
{
"name": "@bbob/react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "../../node_modules/.bin/jest --",
"cover": "../../node_modules/.bin/jest --coverage",
"lint": "../../node_modules/.bin/eslint "
},
"author": "Nikolay Kostyurin <jilizart@gmail.com>",
"license": "MIT"
}
+3
View File
@@ -0,0 +1,3 @@
function BBob() {
}