{"id":13515509,"url":"https://github.com/JiLiZART/BBob","last_synced_at":"2025-03-31T04:37:11.005Z","repository":{"id":33118602,"uuid":"136083545","full_name":"JiLiZART/BBob","owner":"JiLiZART","description":"⚡️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 ","archived":false,"fork":false,"pushed_at":"2025-03-14T19:51:41.000Z","size":5226,"stargazers_count":172,"open_issues_count":19,"forks_count":20,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-24T17:11:11.646Z","etag":null,"topics":["ast","bbcode","bbcode-parser","bbob","html","javascript","parse","parser","posthtml","react","reactjs","tree","vue","vuejs"],"latest_commit_sha":null,"homepage":"https://codepen.io/JiLiZART/full/vzMvpd","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JiLiZART.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-04T21:13:58.000Z","updated_at":"2025-03-14T19:50:05.000Z","dependencies_parsed_at":"2023-10-23T11:31:37.140Z","dependency_job_id":"ed0f9266-ab05-431e-a91b-4d49de97c272","html_url":"https://github.com/JiLiZART/BBob","commit_stats":{"total_commits":301,"total_committers":15,"mean_commits":"20.066666666666666","dds":0.5514950166112957,"last_synced_commit":"ccab54a4547b67d0ea61644e36ca57fdbe8c6491"},"previous_names":[],"tags_count":208,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiLiZART%2FBBob","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiLiZART%2FBBob/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiLiZART%2FBBob/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiLiZART%2FBBob/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JiLiZART","download_url":"https://codeload.github.com/JiLiZART/BBob/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246418657,"owners_count":20773934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ast","bbcode","bbcode-parser","bbob","html","javascript","parse","parser","posthtml","react","reactjs","tree","vue","vuejs"],"created_at":"2024-08-01T05:01:12.216Z","updated_at":"2025-03-31T04:37:10.996Z","avatar_url":"https://github.com/JiLiZART.png","language":"TypeScript","readme":"\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"BBob a BBCode processor\" src=\"https://github.com/JiLiZART/bbob/blob/master/.github/card.png?raw=true\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nBBob is a tool to parse and transform [BBCode](https://en.wikipedia.org/wiki/BBCode)\nwritten in pure javascript, no dependencies\n\u003c/p\u003e\n\n[![Tests](https://github.com/JiLiZART/BBob/actions/workflows/test.yml/badge.svg)](https://github.com/JiLiZART/BBob/actions/workflows/test.yml)\n[![Benchmark](https://github.com/JiLiZART/BBob/actions/workflows/benchmark.yml/badge.svg)](https://github.com/JiLiZART/BBob/actions/workflows/benchmark.yml)\n\u003ca href='https://coveralls.io/github/JiLiZART/BBob?branch=master'\u003e\n    \u003cimg src='https://coveralls.io/repos/github/JiLiZART/BBob/badge.svg?branch=master' alt='Coverage Status' /\u003e\n\u003c/a\u003e\n\u003ca href=\"https://www.codefactor.io/repository/github/jilizart/bbob\"\u003e\n  \u003cimg src=\"https://www.codefactor.io/repository/github/jilizart/bbob/badge\" alt=\"CodeFactor\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://snyk.io/test/github/JiLiZART/bbob?targetFile=package.json\"\u003e\n  \u003cimg src=\"https://snyk.io/test/github/JiLiZART/bbob/badge.svg?targetFile=package.json\" alt=\"Known Vulnerabilities\"\u003e\n\u003c/a\u003e\n\n## Packages\n\n| Package              | Status                                                     | Size                        | Description               |\n|----------------------|------------------------------------------------------------|-----------------------------|---------------------------|\n| @bbob/react          | [![@bbob/react-status]][@bbob/react-package]               | ![@bbob/react-size]         | React renderer            |\n| @bbob/preset-react   | [![@bbob/preset-react-status]][@bbob/preset-react-package] | ![@bbob/preset-react-size]  | React default tags preset |\n| @bbob/vue3           | [![@bbob/vue3-status]][@bbob/vue3-package]                 | ![@bbob/vue3-size]          | Vue 3 renderer            |\n| @bbob/vue2           | [![@bbob/vue2-status]][@bbob/vue2-package]                 | ![@bbob/vue2-size]          | Vue 2 renderer            |\n| @bbob/preset-vue     | [![@bbob/preset-vue-status]][@bbob/preset-vue-package]     | ![@bbob/preset-vue-size]    | Vue default tags preset   |\n| @bbob/html           | [![@bbob/html-status]][@bbob/html-package]                 | ![@bbob/html-size]          | HTML renderer             |\n| @bbob/preset-html5   | [![@bbob/preset-html5-status]][@bbob/preset-html5-package] | ![@bbob/preset-html5-size]  | HTML5 default tags preset |\n| @bbob/core           | [![@bbob/core-status]][@bbob/core-package]                 | ![@bbob/core-size]          | Core package              |\n\n[@bbob/core-status]: https://img.shields.io/npm/v/@bbob/core.svg\n\n[@bbob/react-status]: https://img.shields.io/npm/v/@bbob/react.svg\n[@bbob/preset-react-status]: https://img.shields.io/npm/v/@bbob/preset-react.svg\n\n[@bbob/vue3-status]: https://img.shields.io/npm/v/@bbob/vue3.svg\n[@bbob/vue2-status]: https://img.shields.io/npm/v/@bbob/vue2.svg\n[@bbob/preset-vue-status]: https://img.shields.io/npm/v/@bbob/preset-vue.svg\n\n[@bbob/html-status]: https://img.shields.io/npm/v/@bbob/html.svg\n[@bbob/preset-html5-status]: https://img.shields.io/npm/v/@bbob/preset-html5.svg\n\n\n[@bbob/core-size]: https://badgen.net/bundlephobia/minzip/@bbob/core\n\n[@bbob/react-size]: https://badgen.net/bundlephobia/minzip/@bbob/react\n[@bbob/preset-react-size]: https://badgen.net/bundlephobia/minzip/@bbob/preset-react\n\n[@bbob/vue3-size]: https://badgen.net/bundlephobia/minzip/@bbob/vue3\n[@bbob/vue2-size]: https://badgen.net/bundlephobia/minzip/@bbob/vue2\n[@bbob/preset-vue-size]: https://badgen.net/bundlephobia/minzip/@bbob/preset-vue\n\n[@bbob/html-size]: https://badgen.net/bundlephobia/minzip/@bbob/html\n[@bbob/preset-html5-size]: https://badgen.net/bundlephobia/minzip/@bbob/preset-html5\n\n[@bbob/core-package]: https://npmjs.com/package/@bbob/core\n\n[@bbob/react-package]: https://npmjs.com/package/@bbob/react\n[@bbob/preset-react-package]: https://npmjs.com/package/@bbob/preset-react\n\n[@bbob/vue3-package]: https://npmjs.com/package/@bbob/vue3\n[@bbob/vue2-package]: https://npmjs.com/package/@bbob/vue2\n[@bbob/preset-vue-package]: https://npmjs.com/package/@bbob/preset-vue\n\n[@bbob/html-package]: https://npmjs.com/package/@bbob/html\n[@bbob/preset-html5-package]: https://npmjs.com/package/@bbob/preset-html5\n\n[DEMO Playground](https://codepen.io/JiLiZART/full/vzMvpd)\n\n## Table of contents\n* [Usage](#usage)\n  * [Basic usage](#basic-usage)\n  * [React usage](#react-usage)\n  * [Vue 2 usage](#vue2-usage)\n* [Parse Options](#parse-options)\n* [Presets](#presets)\n   * [Create your own preset](#create-preset)\n   * [HTML Preset](#html-preset)\n   * [React Preset](#react-preset)\n* [React usage](#react)\n   * [Component](#react-component)\n   * [Render prop](#react-render)\n* [PostHTML usage](#posthtml)\n* [Create Plugin](#plugin)\n* [Benchmarks](#benchmarks)\n* [Donate](#donations)\n\n### Basic usage \u003ca name=\"basic-usage\"\u003e\u003c/a\u003e\n\n```shell\nnpm i @bbob/html @bbob/preset-html5\n```\n\n```js\nimport bbobHTML from '@bbob/html'\nimport presetHTML5 from '@bbob/preset-html5'\n\nconst processed = bbobHTML(`[i]Text[/i]`, presetHTML5())\n\nconsole.log(processed); // \u003cspan style=\"font-style: italic;\"\u003eText\u003c/span\u003e\n```\n\n### React usage \u003ca name=\"react-usage\"\u003e\u003c/a\u003e\n\n```shell\nnpm i @bbob/react @bbob/preset-react\n```\n\n```jsx\nimport React from 'react'\nimport BBCode from '@bbob/react';\nimport presetReact from '@bbob/preset-react';\n\nconst plugins = [presetReact()];\n\nexport default () =\u003e (\n    \u003cBBCode plugins={plugins}\u003e\n    [table]\n      [tr]\n          [td]table 1[/td]\n          [td]table 2[/td]\n      [/tr]\n      [tr]\n          [td]table 3[/td]\n          [td]table 4[/td]\n      [/tr]\n    [/table]\n    \u003c/BBCode\u003e\n)\n```\n\n```jsx\nimport { render } from '@bbob/react'\n\nexport default () =\u003e render(`\n[table]\n  [tr]\n      [td]table 1[/td]\n      [td]table 2[/td]\n  [/tr]\n  [tr]\n      [td]table 3[/td]\n      [td]table 4[/td]\n  [/tr]\n[/table]\n`)\n```\n\n### Vue 2 usage \u003ca name=\"vue2-usage\"\u003e\u003c/a\u003e\n\n```shell\nnpm i @bbob/vue2 @bbob/preset-vue\n```\n\n```js\nimport Vue from 'vue'\nimport VueBbob from '@bbob/vue2';\n\nVue.use(VueBbob);\n```\n\n```html\n\u003ctemplate\u003e\n  \u003cdiv class=\"html\"\u003e\n    \u003ch2\u003eGenerated HTML here\u003c/h2\u003e\n    \u003cbbob-bbcode container=\"div\" :plugins=\"plugins\"\u003e{{ bbcode }}\u003c/bbob-bbcode\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\u003cscript\u003e\n  import Vue from 'vue'\n  import preset from '@bbob/preset-vue'\n  \n  export default Vue.extend({\n    name: 'App',\n    data() {\n      return {\n        bbcode: 'Text [b]bolded[/b] and [i]Some Name[/i]',\n        plugins: [\n          preset()\n        ],\n      }\n    }\n  })\n\u003c/script\u003e\n```\n\nMore examples available in \u003ca href=\"https://github.com/JiLiZART/BBob/tree/master/examples\"\u003eexamples folder\u003c/a\u003e\n\n### Parse options \u003ca name=\"parse-options\"\u003e\u003c/a\u003e\n\n#### onlyAllowTags\n\nParse only allowed tags\n\n```js\nimport bbobHTML from '@bbob/html'\nimport presetHTML5 from '@bbob/preset-html5'\n\nconst processed = bbobHTML(`[i][b]Text[/b][/i]`, presetHTML5(), { onlyAllowTags: ['i'] })\n\nconsole.log(processed); // \u003cspan style=\"font-style: italic;\"\u003e[b]Text[/b]\u003c/span\u003e\n```\n\n#### contextFreeTags\n\nEnable context free mode that ignores parsing all tags inside given tags\n\n```js\nimport bbobHTML from '@bbob/html'\nimport presetHTML5 from '@bbob/preset-html5'\n\nconst processed = bbobHTML(`[b]Text[/b][code][b]Text[/b][/code]`, presetHTML5(), { contextFreeTags: ['code'] })\n\nconsole.log(processed); // \u003cspan style=\"font-weight: bold;\"\u003eText\u003c/span\u003e\u003cpre\u003e[b]Text[/b]\u003c/pre\u003e\n```\n\n#### enableEscapeTags\n\nEnable escape support for tags\n\n```js\nimport bbobHTML from '@bbob/html'\nimport presetHTML5 from '@bbob/preset-html5'\n\nconst processed = bbobHTML(`[b]Text[/b]'\\\\[b\\\\]Text\\\\[/b\\\\]'`, presetHTML5(), { enableEscapeTags: true })\n\nconsole.log(processed); // \u003cspan style=\"font-weight: bold;\"\u003eText\u003c/span\u003e[b]Text[/b]\n```\n\n#### caseFreeTags\n\nAllows to parse case insensitive tags like `[h1]some[/H1]` -\u003e `\u003ch1\u003esome\u003c/h1\u003e`\n\n```js\nimport bbobHTML from '@bbob/html'\nimport presetHTML5 from '@bbob/preset-html5'\n\nconst processed = bbobHTML(`[h1]some[/H1]`, presetHTML5(), { caseFreeTags: true })\n\nconsole.log(processed); // \u003ch1\u003esome\u003c/h1\u003e\n```\n\n```js\nimport bbobHTML from '@bbob/html'\nimport presetHTML5 from '@bbob/preset-html5'\n\nconst processed = bbobHTML(`[b]Text[/b]'\\\\[b\\\\]Text\\\\[/b\\\\]'`, presetHTML5(), { enableEscapeTags: true })\n\nconsole.log(processed); // \u003cspan style=\"font-weight: bold;\"\u003eText\u003c/span\u003e[b]Text[/b]\n```\n\n\n### Presets \u003ca name=\"basic\"\u003e\u003c/a\u003e\n\nIts a way to transform parsed BBCode AST tree to another tree by rules in preset\n\n#### Create your own preset \u003ca name=\"create-preset\"\u003e\u003c/a\u003e\n\n```js\nimport { createPreset } from '@bbob/preset'\n\nexport default createPreset({\n  quote: (node) =\u003e ({\n    tag: 'blockquote',\n    attrs: node.attrs,\n    content: [{\n      tag: 'p',\n      attrs: {},\n      content: node.content,\n    }],\n  }),\n})\n```\n\n#### HTML Preset \u003ca name=\"html-preset\"\u003e\u003c/a\u003e\n\nAlso you can use predefined preset for HTML\n\n```js\nimport html5Preset from '@bbob/preset-html5/es'\nimport { render } from '@bbob/html/es'\nimport bbob from '@bbob/core'\n\nconsole.log(bbob(html5Preset()).process(`[quote]Text[/quote]`, { render }).html) // \u003cblockquote\u003e\u003cp\u003eText\u003c/p\u003e\u003c/blockquote\u003e\n```\n\n#### React Preset \u003ca name=\"react-preset\"\u003e\u003c/a\u003e\n\nAlso you can use predefined preset for React\n\n```js\nimport reactPreset from \"@bbob/preset-react\";\nimport reactRender from \"@bbob/react/es/render\";\n\nconst preset = reactPreset.extend((tags, options) =\u003e ({\n  ...tags,\n  quote: node =\u003e ({\n    tag: \"blockquote\",\n    content: node.content\n  })\n}));\n\nconst result = reactRender(`[quote]Text[/quote]`, reactPreset());\n\n/* \nIt produces a VDOM Nodes equal to\nReact.createElement('blockquote', 'Text')\n*/\ndocument.getElementById(\"root\").innerHTML = JSON.stringify(result, 4);\n```\n\n[![Edit lp7q9yj0lq](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/lp7q9yj0lq)\n\n### React usage \u003ca name=\"react\"\u003e\u003c/a\u003e\n\n#### Component \u003ca name=\"react-component\"\u003e\u003c/a\u003e\n\nOr you can use React Component\n\n```js\nimport React from 'react'\nimport { render } from 'react-dom'\n\nimport BBCode from '@bbob/react/es/Component'\nimport reactPreset from '@bbob/preset-react/es'\n\nconst MyComponent = () =\u003e (\n  \u003cBBCode plugins={[reactPreset()]} options={{ onlyAllowTags: ['i'] }}\u003e\n    [quote]Text[/quote]\n  \u003c/BBCode\u003e\n)\n\nrender(\u003cMyComponent /\u003e) // \u003cdiv\u003e\u003cblockquote\u003e\u003cp\u003eText\u003c/p\u003e\u003c/blockquote\u003e\u003c/div\u003e\n```\n[![Edit 306pzr9k5p](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/306pzr9k5p)\n\n\n#### Render prop \u003ca name=\"react-render\"\u003e\u003c/a\u003e\n\nOr pass result as render prop\n\n```js\nimport React from \"react\";\nimport { render } from 'react-dom'\n\nimport reactRender from '@bbob/react/es/render'\nimport reactPreset from '@bbob/preset-react/es'\n\nconst toReact = input =\u003e reactRender(input, reactPreset())\n\nconst text = toReact('[b]Super [i]easy[/i][/b] [u]to[/u] render')\n\nconst App = ({ renderProp }) =\u003e (\n  \u003cspan\u003e{text}\u003c/span\u003e\n)\n\nrender(\u003cApp /\u003e) // \u003cspan\u003e\u003cspan style=\"font-weight: bold;\"\u003eSuper \u003cspan style=\"font-style: italic;\"\u003eeasy\u003c/span\u003e\u003c/span\u003e \u003cspan style=\"text-decoration: underline;\"\u003eto\u003c/span\u003e render\u003c/span\u003e\n```\n\n[![Edit x7w52lqmzz](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/jovial-cohen-bvo08)\n\n### PostHTML usage \u003ca name=\"posthtml\"\u003e\u003c/a\u003e\n\n### Create Plugin \u003ca name=\"plugin\"\u003e\u003c/a\u003e\n\nFor example lets parse all strings that similar to links like \"https://some-site.com\"\n\n```js\nimport { createRoot } from \"react-dom/client\";\n\nimport BBCode from \"@bbob/react/es/Component\";\nimport TagNode from \"@bbob/plugin-helper/es/TagNode\";\nimport { isStringNode } from \"@bbob/plugin-helper/es\";\n\nconst URL_RE = new RegExp(\n  `([--:\\\\w?@%\u0026+~#=]+\\\\/*\\\\.[a-z]{2,4}\\\\/{0,2})((?:[?\u0026](?:\\\\w+)=(?:\\\\w+))+|[^^).|,][--:\\\\w?@%\u0026+~#=()_]+)?`,\n  \"g\"\n);\n\nconst isValidUrl = (url) =\u003e URL_RE.test(url);\n\nconst linkParsePlugin = (tree) =\u003e {\n  return tree.walk((node) =\u003e {\n    if (isStringNode(node) \u0026\u0026 isValidUrl(node)) {\n      return TagNode.create(\n        \"a\",\n        {\n          href: node\n        },\n        `Url to: ${node}`\n      );\n    }\n\n    return node;\n  });\n};\n\nconst rootElement = document.getElementById(\"root\");\nconst root = createRoot(rootElement);\n\nroot.render(\n  \u003cBBCode plugins={[linkParsePlugin]}\u003e\n    https://github.com/JiLiZART/BBob Other text without link\n  \u003c/BBCode\u003e\n);\n```\n\n[![Edit x7w52lqmzz](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/bbob-plugin-example-dmq1bh)\n\n\n### Benchmarks \u003ca name=\"benchmarks\"\u003e\u003c/a\u003e\n\nTo test on your machine run\n```shell\nnpm run build\nnode benchmark\n```\n\nTested on Node v20.11.1\n\n| Package              | Ops/sec              |\n|----------------------|----------------------|\n| regex/parser         | `6 ops/sec`          |\n| ya-bbcode            | `11 ops/sec`         |\n| xbbcode/parser       | `102 ops/sec`        |\n| @bbob/parser         | `174 ops/sec`        |\n\n[Checkout Benckmark job results](https://github.com/JiLiZART/BBob/actions/workflows/benchmark.yml)\n\n### Donations \u003ca name=\"donations\"\u003e\u003c/a\u003e\n\nYou can support this projecti with donation in:\n\n*Bitcoin:* `bc1qx34sx3zmfd5e2km607p8s8t30d4rt33d2l9pwt`\n\n*USDT(TRC20):* `TT94uVjJho8n47xbdfNYz6vdebgmKFpxAT`\n\n\nAlso thanks to support \n\n![Jetbrains IDEA](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_square.svg)\n\nDeveloped with \u003c3 using JetBrains\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJiLiZART%2FBBob","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJiLiZART%2FBBob","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJiLiZART%2FBBob/lists"}