Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/JiLiZART/BBob

⚡️Blazing fast js bbcode parser, that transforms and parses bbcode to AST and transform it to HTML, React, Vue with plugin support in pure javascript, no dependencies
https://github.com/JiLiZART/BBob

ast bbcode bbcode-parser bbob html javascript parse parser posthtml react reactjs tree vue vuejs

Last synced: 9 days ago
JSON representation

⚡️Blazing fast js bbcode parser, that transforms and parses bbcode to AST and transform it to HTML, React, Vue with plugin support in pure javascript, no dependencies

Awesome Lists containing this project

README

        


BBob a BBCode processor

BBob is a tool to parse and transform [BBCode](https://en.wikipedia.org/wiki/BBCode)
written in pure javascript, no dependencies

[![Tests](https://github.com/JiLiZART/BBob/actions/workflows/test.yml/badge.svg)](https://github.com/JiLiZART/BBob/actions/workflows/test.yml)
[![Benchmark](https://github.com/JiLiZART/BBob/actions/workflows/benchmark.yml/badge.svg)](https://github.com/JiLiZART/BBob/actions/workflows/benchmark.yml)

Coverage Status


CodeFactor


Known Vulnerabilities

## Packages

| Package | Status | Size | Description |
|----------------------|------------------------------------------------------------|-----------------------------|---------------------------|
| @bbob/react | [![@bbob/react-status]][@bbob/react-package] | ![@bbob/react-size] | React renderer |
| @bbob/preset-react | [![@bbob/preset-react-status]][@bbob/preset-react-package] | ![@bbob/preset-react-size] | React default tags preset |
| @bbob/vue3 | [![@bbob/vue3-status]][@bbob/vue3-package] | ![@bbob/vue3-size] | Vue 3 renderer |
| @bbob/vue2 | [![@bbob/vue2-status]][@bbob/vue2-package] | ![@bbob/vue2-size] | Vue 2 renderer |
| @bbob/preset-vue | [![@bbob/preset-vue-status]][@bbob/preset-vue-package] | ![@bbob/preset-vue-size] | Vue default tags preset |
| @bbob/html | [![@bbob/html-status]][@bbob/html-package] | ![@bbob/html-size] | HTML renderer |
| @bbob/preset-html5 | [![@bbob/preset-html5-status]][@bbob/preset-html5-package] | ![@bbob/preset-html5-size] | HTML5 default tags preset |
| @bbob/core | [![@bbob/core-status]][@bbob/core-package] | ![@bbob/core-size] | Core package |

[@bbob/core-status]: https://img.shields.io/npm/v/@bbob/core.svg

[@bbob/react-status]: https://img.shields.io/npm/v/@bbob/react.svg
[@bbob/preset-react-status]: https://img.shields.io/npm/v/@bbob/preset-react.svg

[@bbob/vue3-status]: https://img.shields.io/npm/v/@bbob/vue3.svg
[@bbob/vue2-status]: https://img.shields.io/npm/v/@bbob/vue2.svg
[@bbob/preset-vue-status]: https://img.shields.io/npm/v/@bbob/preset-vue.svg

[@bbob/html-status]: https://img.shields.io/npm/v/@bbob/html.svg
[@bbob/preset-html5-status]: https://img.shields.io/npm/v/@bbob/preset-html5.svg

[@bbob/core-size]: https://badgen.net/bundlephobia/minzip/@bbob/core

[@bbob/react-size]: https://badgen.net/bundlephobia/minzip/@bbob/react
[@bbob/preset-react-size]: https://badgen.net/bundlephobia/minzip/@bbob/preset-react

[@bbob/vue3-size]: https://badgen.net/bundlephobia/minzip/@bbob/vue3
[@bbob/vue2-size]: https://badgen.net/bundlephobia/minzip/@bbob/vue2
[@bbob/preset-vue-size]: https://badgen.net/bundlephobia/minzip/@bbob/preset-vue

[@bbob/html-size]: https://badgen.net/bundlephobia/minzip/@bbob/html
[@bbob/preset-html5-size]: https://badgen.net/bundlephobia/minzip/@bbob/preset-html5

[@bbob/core-package]: https://npmjs.com/package/@bbob/core

[@bbob/react-package]: https://npmjs.com/package/@bbob/react
[@bbob/preset-react-package]: https://npmjs.com/package/@bbob/preset-react

[@bbob/vue3-package]: https://npmjs.com/package/@bbob/vue3
[@bbob/vue2-package]: https://npmjs.com/package/@bbob/vue2
[@bbob/preset-vue-package]: https://npmjs.com/package/@bbob/preset-vue

[@bbob/html-package]: https://npmjs.com/package/@bbob/html
[@bbob/preset-html5-package]: https://npmjs.com/package/@bbob/preset-html5

[DEMO Playground](https://codepen.io/JiLiZART/full/vzMvpd)

## Table of contents
* [Usage](#usage)
* [Basic usage](#basic-usage)
* [React usage](#react-usage)
* [Vue 2 usage](#vue2-usage)
* [Parse Options](#parse-options)
* [Presets](#presets)
* [Create your own preset](#create-preset)
* [HTML Preset](#html-preset)
* [React Preset](#react-preset)
* [React usage](#react)
* [Component](#react-component)
* [Render prop](#react-render)
* [PostHTML usage](#posthtml)
* [Create Plugin](#plugin)
* [Benchmarks](#benchmarks)
* [Donate](#donations)

### Basic usage

```shell
npm i @bbob/html @bbob/preset-html5
```

```js
import bbobHTML from '@bbob/html'
import presetHTML5 from '@bbob/preset-html5'

const processed = bbobHTML(`[i]Text[/i]`, presetHTML5())

console.log(processed); // Text
```

### React usage

```shell
npm i @bbob/react @bbob/preset-react
```

```jsx
import React from 'react'
import BBCode from '@bbob/react';
import presetReact from '@bbob/preset-react';

const plugins = [presetReact()];

export default () => (

[table]
[tr]
[td]table 1[/td]
[td]table 2[/td]
[/tr]
[tr]
[td]table 3[/td]
[td]table 4[/td]
[/tr]
[/table]

)
```

```jsx
import { render } from '@bbob/react'

export default () => render(`
[table]
[tr]
[td]table 1[/td]
[td]table 2[/td]
[/tr]
[tr]
[td]table 3[/td]
[td]table 4[/td]
[/tr]
[/table]
`)
```

### Vue 2 usage

```shell
npm i @bbob/vue2 @bbob/preset-vue
```

```js
import Vue from 'vue'
import VueBbob from '@bbob/vue2';

Vue.use(VueBbob);
```

```html


Generated HTML here


{{ bbcode }}

import Vue from 'vue'
import preset from '@bbob/preset-vue'

export default Vue.extend({
name: 'App',
data() {
return {
bbcode: 'Text [b]bolded[/b] and [i]Some Name[/i]',
plugins: [
preset()
],
}
}
})

```

More examples available in examples folder

### Parse options

#### onlyAllowTags

Parse only allowed tags

```js
import bbobHTML from '@bbob/html'
import presetHTML5 from '@bbob/preset-html5'

const processed = bbobHTML(`[i][b]Text[/b][/i]`, presetHTML5(), { onlyAllowTags: ['i'] })

console.log(processed); // [b]Text[/b]
```

#### contextFreeTags

Enable context free mode that ignores parsing all tags inside given tags

```js
import bbobHTML from '@bbob/html'
import presetHTML5 from '@bbob/preset-html5'

const processed = bbobHTML(`[b]Text[/b][code][b]Text[/b][/code]`, presetHTML5(), { contextFreeTags: ['code'] })

console.log(processed); // Text

[b]Text[/b]

```

#### enableEscapeTags

Enable escape support for tags

```js
import bbobHTML from '@bbob/html'
import presetHTML5 from '@bbob/preset-html5'

const processed = bbobHTML(`[b]Text[/b]'\\[b\\]Text\\[/b\\]'`, presetHTML5(), { enableEscapeTags: true })

console.log(processed); // Text[b]Text[/b]
```

#### caseFreeTags

Allows to parse case insensitive tags like `[h1]some[/H1]` -> `

some

`

```js
import bbobHTML from '@bbob/html'
import presetHTML5 from '@bbob/preset-html5'

const processed = bbobHTML(`[h1]some[/H1]`, presetHTML5(), { caseFreeTags: true })

console.log(processed); //

some


```

```js
import bbobHTML from '@bbob/html'
import presetHTML5 from '@bbob/preset-html5'

const processed = bbobHTML(`[b]Text[/b]'\\[b\\]Text\\[/b\\]'`, presetHTML5(), { enableEscapeTags: true })

console.log(processed); // Text[b]Text[/b]
```

### Presets

Its a way to transform parsed BBCode AST tree to another tree by rules in preset

#### Create your own preset

```js
import { createPreset } from '@bbob/preset'

export default createPreset({
quote: (node) => ({
tag: 'blockquote',
attrs: node.attrs,
content: [{
tag: 'p',
attrs: {},
content: node.content,
}],
}),
})
```

#### HTML Preset

Also you can use predefined preset for HTML

```js
import html5Preset from '@bbob/preset-html5/es'
import { render } from '@bbob/html/es'
import bbob from '@bbob/core'

console.log(bbob(html5Preset()).process(`[quote]Text[/quote]`, { render }).html) //

Text


```

#### React Preset

Also you can use predefined preset for React

```js
import reactPreset from "@bbob/preset-react";
import reactRender from "@bbob/react/es/render";

const preset = reactPreset.extend((tags, options) => ({
...tags,
quote: node => ({
tag: "blockquote",
content: node.content
})
}));

const result = reactRender(`[quote]Text[/quote]`, reactPreset());

/*
It produces a VDOM Nodes equal to
React.createElement('blockquote', 'Text')
*/
document.getElementById("root").innerHTML = JSON.stringify(result, 4);
```

[![Edit lp7q9yj0lq](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/lp7q9yj0lq)

### React usage

#### Component

Or you can use React Component

```js
import React from 'react'
import { render } from 'react-dom'

import BBCode from '@bbob/react/es/Component'
import reactPreset from '@bbob/preset-react/es'

const MyComponent = () => (

[quote]Text[/quote]

)

render() //

Text


```
[![Edit 306pzr9k5p](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/306pzr9k5p)

#### Render prop

Or pass result as render prop

```js
import React from "react";
import { render } from 'react-dom'

import reactRender from '@bbob/react/es/render'
import reactPreset from '@bbob/preset-react/es'

const toReact = input => reactRender(input, reactPreset())

const text = toReact('[b]Super [i]easy[/i][/b] [u]to[/u] render')

const App = ({ renderProp }) => (
{text}
)

render() // Super easy to render
```

[![Edit x7w52lqmzz](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/jovial-cohen-bvo08)

### PostHTML usage

### Create Plugin

For example lets parse all strings that similar to links like "https://some-site.com"

```js
import { createRoot } from "react-dom/client";

import BBCode from "@bbob/react/es/Component";
import TagNode from "@bbob/plugin-helper/es/TagNode";
import { isStringNode } from "@bbob/plugin-helper/es";

const URL_RE = new RegExp(
`([--:\\w?@%&+~#=]+\\/*\\.[a-z]{2,4}\\/{0,2})((?:[?&](?:\\w+)=(?:\\w+))+|[^^).|,][--:\\w?@%&+~#=()_]+)?`,
"g"
);

const isValidUrl = (url) => URL_RE.test(url);

const linkParsePlugin = (tree) => {
return tree.walk((node) => {
if (isStringNode(node) && isValidUrl(node)) {
return TagNode.create(
"a",
{
href: node
},
`Url to: ${node}`
);
}

return node;
});
};

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(

https://github.com/JiLiZART/BBob Other text without link

);
```

[![Edit x7w52lqmzz](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/bbob-plugin-example-dmq1bh)

### Benchmarks

To test on your machine run
```shell
npm run build
node benchmark
```

Tested on Node v20.11.1

| Package | Ops/sec |
|----------------------|----------------------|
| regex/parser | `6 ops/sec` |
| ya-bbcode | `11 ops/sec` |
| xbbcode/parser | `102 ops/sec` |
| @bbob/parser | `174 ops/sec` |

[Checkout Benckmark job results](https://github.com/JiLiZART/BBob/actions/workflows/benchmark.yml)

### Donations

You can support this projecti with donation in:

*Bitcoin:* `bc1qx34sx3zmfd5e2km607p8s8t30d4rt33d2l9pwt`

*USDT(TRC20):* `TT94uVjJho8n47xbdfNYz6vdebgmKFpxAT`

Also thanks to support

![Jetbrains IDEA](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_square.svg)

Developed with <3 using JetBrains