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

fix(#206): TagNode.create now with null content argument by default (#233)

* fix: TagNode.create with null content by default

* Create five-meals-sing.md

* fix: tests

* fix(preset): types inference

* fix: preset types

* fix: preset types

* fix: lock file, parser and utils

* refactor: move types to separate package

* fix(preset): add @bbob/core to dev deps

* fix(preset): lock file

* test(preset-vue): create tags

* test(preset-vue): tests

* chore(nx): fix nx cover deps

* chore: changesets
This commit is contained in:
Nikolay Kost
2024-06-24 01:32:15 +03:00
committed by GitHub
parent 95d9b8a2ba
commit 270f5645f8
58 changed files with 657 additions and 428 deletions
+27
View File
@@ -0,0 +1,27 @@
---
"@bbob/plugin-helper": minor
"@bbob/preset-html5": minor
"@bbob/preset-react": minor
"@bbob/preset-vue": minor
"@bbob/parser": minor
"@bbob/preset": minor
"@bbob/react": minor
"@bbob/core": minor
"@bbob/html": minor
"@bbob/vue2": minor
"@bbob/vue3": minor
"@bbob/cli": minor
---
** BREAKING CHANGE **
`TagNode.create` method now by default pass `null` to content instead of empty array `[]`
```js
// new behavior
TagNode.create('img').toString() // -> [img]
// old behavior
TagNode.create('img', {}, []).toString() // -> [img][/img]
```
Migrate all calls of `TagNode.create('test-tag')` to `TagNode.create('test-tag', {}, [])
+18
View File
@@ -0,0 +1,18 @@
/* eslint-disable global-require */
const parser = require('@bbob/parser');
const stub = require('./test/stub');
const passes = 100;
const results = new Array(passes);
const lexer = parser.createLexer;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < passes; i++) {
results[i] = parser.parse(stub, {
onlyAllowTags: ['ch'],
createTokenizer: lexer,
});
}
console.log(results.length);
+3 -1
View File
@@ -6,7 +6,8 @@
"test": "test"
},
"scripts": {
"start": "node index.js"
"start": "node index.js",
"cpupro": "node --require cpupro benchmark.js"
},
"author": {
"name": "Nikolay Kostyurin <jilizart@gmail.com>",
@@ -18,6 +19,7 @@
"benchmark": "2.1.4",
"picocolors": "1.0.0",
"xbbcode-parser": "0.1.2",
"cpupro": "*",
"ya-bbcode": "1.0.12"
}
}
+2 -1
View File
@@ -16,7 +16,8 @@
"packages/bbob-preset-vue",
"packages/bbob-react",
"packages/bbob-vue2",
"packages/bbob-vue3"
"packages/bbob-vue3",
"packages/bbob-types"
],
"publishConfig": {
"access": "public",
+5 -10
View File
@@ -5,27 +5,25 @@
"^types"
],
"outputs": ["{projectRoot}/types"],
"cache": true
},
"build": {
"dependsOn": [
"^types",
"^build:commonjs",
"^build:es",
"^build:commonjs",
"^build:umd"
],
"outputs": ["{projectRoot}/lib", "{projectRoot}/es", "{projectRoot}/dist"],
"cache": true
},
"test": {
"dependsOn": [
"^build",
"build",
"^test"
]
},
"cover": {
"dependsOn": [
"^build",
"build",
"^cover"
],
"outputs": ["{projectRoot}/coverage"]
@@ -37,26 +35,23 @@
},
"build:commonjs": {
"dependsOn": [
"^build:es",
"build:es",
"^build:commonjs"
],
"outputs": ["{projectRoot}/lib"],
"cache": true
},
"build:es": {
"dependsOn": [
"^build:es"
],
"outputs": ["{projectRoot}/es"],
"cache": true
},
"build:umd": {
"dependsOn": [
"^build:es",
"build:es",
"^build:umd"
],
"outputs": ["{projectRoot}/dist"],
"cache": true
}
},
"$schema": "./node_modules/nx/schemas/nx-schema.json",
+1
View File
@@ -47,6 +47,7 @@
"build:umd": "pkg-task",
"build": "pkg-task",
"test": "pkg-task",
"cover": "pkg-task",
"lint": "pkg-task",
"size": "pkg-task",
"bundlesize": "pkg-task",
+2 -1
View File
@@ -21,7 +21,8 @@
],
"dependencies": {
"@bbob/parser": "*",
"@bbob/plugin-helper": "*"
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},
"main": "lib/index.js",
"module": "es/index.js",
+10 -6
View File
@@ -1,13 +1,17 @@
import type {
BBobCore,
BBobCoreOptions,
BBobCoreTagNodeTree,
BBobPlugins,
IterateCallback,
NodeContent,
PartialNodeContent
} from "@bbob/types";
import { parse } from '@bbob/parser';
import { iterate, match } from './utils';
import { C1, C2 } from './errors'
import type { IterateCallback } from './utils';
import type { NodeContent, PartialNodeContent } from "@bbob/plugin-helper";
import type { BBobCore, BBobCoreOptions, BBobCoreTagNodeTree, BBobPlugins } from "./types";
export * from './types'
export function createTree<Options extends BBobCoreOptions = BBobCoreOptions>(tree: NodeContent[], options: Options) {
const extendedTree = tree as BBobCoreTagNodeTree
-57
View File
@@ -1,57 +0,0 @@
import type { ParseOptions, TagNode } from "@bbob/parser";
import type {
NodeContent,
PartialNodeContent,
TagNodeTree,
} from "@bbob/plugin-helper";
import type { IterateCallback, iterate } from "./utils";
export interface BBobCoreOptions<
Data = unknown | null,
Options extends ParseOptions = ParseOptions
> extends ParseOptions {
skipParse?: boolean;
parser?: (source: string, options?: Options) => TagNode[];
render?: (ast: TagNodeTree, options?: Options) => string;
data?: Data;
}
export interface BbobPluginOptions<
Options extends ParseOptions = ParseOptions
> {
parse: BBobCoreOptions["parser"];
render: (ast: TagNodeTree, options?: Options) => string;
iterate: typeof iterate;
data: unknown | null;
}
export interface BBobPluginFunction {
(tree: BBobCoreTagNodeTree, options: BbobPluginOptions): BBobCoreTagNodeTree;
}
export interface BBobCore<
InputValue = string | TagNode[],
Options extends BBobCoreOptions = BBobCoreOptions
> {
process(
input: InputValue,
opts?: Options
): {
readonly html: string;
tree: BBobCoreTagNodeTree;
raw: TagNode[] | string;
messages: unknown[];
};
}
export interface BBobCoreTagNodeTree extends Array<NodeContent> {
messages: unknown[];
options: BBobCoreOptions;
walk: (cb: IterateCallback<NodeContent>) => BBobCoreTagNodeTree;
match: (
expression: PartialNodeContent | PartialNodeContent[],
cb: IterateCallback<NodeContent>
) => BBobCoreTagNodeTree;
}
export type BBobPlugins = BBobPluginFunction | BBobPluginFunction[];
+2 -2
View File
@@ -1,9 +1,9 @@
/* eslint-disable no-plusplus */
import { IterateCallback } from "@bbob/types";
const isObj = (value: unknown): value is Record<string, unknown> => (typeof value === 'object' && value !== null);
const isBool = (value: unknown): value is boolean => (typeof value === 'boolean');
export type IterateCallback<Content> = (node: Content) => Content
export function iterate<Content, Iterable = ArrayLike<Content> | Content>(t: Iterable, cb: IterateCallback<Content>): Iterable {
const tree = t;
+1 -1
View File
@@ -71,7 +71,7 @@ describe('@bbob/core', () => {
const plugin: BBobPluginFunction = (tree) => tree.walk(node => {
if (node === ':)') {
return TagNode.create('test-tag')
return TagNode.create('test-tag', {}, [])
}
return node
+2 -1
View File
@@ -10,7 +10,8 @@
],
"dependencies": {
"@bbob/core": "*",
"@bbob/plugin-helper": "*"
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},
"main": "lib/index.js",
"module": "es/index.js",
+7 -6
View File
@@ -1,14 +1,15 @@
import core, { BBobCoreOptions, BBobPlugins } from '@bbob/core';
import { attrsToString, isTagNode, TagNode, TagNodeTree } from '@bbob/plugin-helper';
import core from '@bbob/core';
import { attrsToString, isTagNode, TagNode } from '@bbob/plugin-helper';
import type { BBobCoreOptions, BBobPlugins, TagNodeTree } from '@bbob/types';
const SELFCLOSE_END_TAG = '/>';
const CLOSE_START_TAG = '</';
const START_TAG = '<';
const END_TAG = '>';
export type BBobHTMLOptions = {
interface BBobHTMLOptions extends BBobCoreOptions {
stripTags?: boolean
} & BBobCoreOptions
}
function renderNode(node?: TagNodeTree, options?: BBobHTMLOptions): string {
const { stripTags = false } = options || {}
@@ -42,8 +43,8 @@ function renderNode(node?: TagNodeTree, options?: BBobHTMLOptions): string {
return '';
}
export function render(nodes: TagNodeTree, options?: BBobHTMLOptions): string {
if (Array.isArray(nodes)) {
export function render(nodes?: TagNodeTree, options?: BBobHTMLOptions): string {
if (nodes && Array.isArray(nodes)) {
return nodes.reduce<string>((r, node) => r + renderNode(node, options), '')
}
+2 -1
View File
@@ -20,7 +20,8 @@
"types"
],
"dependencies": {
"@bbob/plugin-helper": "*"
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},
"main": "lib/index.js",
"module": "es/index.js",
+6 -5
View File
@@ -3,6 +3,7 @@ import {
CLOSE_BRAKET,
SLASH,
} from '@bbob/plugin-helper';
import type { Token as TokenInterface } from "@bbob/types";
// type, value, line, row,
@@ -87,11 +88,11 @@ const tokenToText = (token: Token) => {
* @export
* @class Token
*/
class Token<TokenValue = string> {
private t: number // type
private v: string // value
private l: number // line
private r: number // row
class Token<TokenValue = string> implements TokenInterface {
readonly t: number // type
readonly v: string // value
readonly l: number // line
readonly r: number // row
constructor(type?: number, value?: TokenValue, row: number = 0, col: number = 0) {
this[TOKEN_LINE_ID] = row;
-1
View File
@@ -2,4 +2,3 @@ export { TagNode } from '@bbob/plugin-helper';
export { default } from './parse';
export * from './parse';
export * from './lexer'
export * from './types'
+29 -19
View File
@@ -10,12 +10,12 @@ import {
EQ,
N,
} from '@bbob/plugin-helper';
import type { LexerOptions, LexerTokenizer } from "@bbob/types";
import {
Token, TYPE_ATTR_NAME, TYPE_ATTR_VALUE, TYPE_NEW_LINE, TYPE_SPACE, TYPE_TAG, TYPE_WORD,
} from './Token';
import { CharGrabber, createCharGrabber, trimChar, unquote } from './utils';
import type { LexerOptions, LexerTokenizer } from "./types";
// for cases <!-- -->
const EM = '!';
@@ -24,15 +24,24 @@ export function createTokenOfType(type: number, value: string, r = 0, cl = 0) {
return new Token(type, value, r, cl)
}
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
const WHITESPACES = [SPACE, TAB];
const SPECIAL_CHARS = [EQ, SPACE, TAB];
const isWhiteSpace = (char: string) => (WHITESPACES.indexOf(char) >= 0);
const isEscapeChar = (char: string) => char === BACKSLASH;
const isSpecialChar = (char: string) => (SPECIAL_CHARS.indexOf(char) >= 0);
const isNewLine = (char: string) => char === N;
const unq = (val: string) => unquote(trimChar(val, QUOTEMARK));
export function createLexer(buffer: string, options: LexerOptions = {}): LexerTokenizer {
const STATE_WORD = 0;
const STATE_TAG = 1;
const STATE_TAG_ATTRS = 2;
const TAG_STATE_NAME = 0;
const TAG_STATE_ATTR = 1;
const TAG_STATE_VALUE = 2;
let row = 0;
let col = 0;
@@ -47,6 +56,7 @@ export function createLexer(buffer: string, options: LexerOptions = {}): LexerTo
const contextFreeTags = (options.contextFreeTags || [])
.filter(Boolean)
.map((tag) => tag.toLowerCase());
const nestedMap = new Map<string, boolean>();
const onToken = options.onToken || (() => {
});
@@ -54,22 +64,14 @@ export function createLexer(buffer: string, options: LexerOptions = {}): LexerTo
const NOT_CHAR_TOKENS = [
openTag, SPACE, TAB, N,
];
const WHITESPACES = [SPACE, TAB];
const SPECIAL_CHARS = [EQ, SPACE, TAB];
const isCharReserved = (char: string) => (RESERVED_CHARS.indexOf(char) >= 0);
const isNewLine = (char: string) => char === N;
const isWhiteSpace = (char: string) => (WHITESPACES.indexOf(char) >= 0);
const isCharToken = (char: string) => (NOT_CHAR_TOKENS.indexOf(char) === -1);
const isSpecialChar = (char: string) => (SPECIAL_CHARS.indexOf(char) >= 0);
const isEscapableChar = (char: string) => (char === openTag || char === closeTag || char === BACKSLASH);
const isEscapeChar = (char: string) => char === BACKSLASH;
const onSkip = () => {
col++;
};
const unq = (val: string) => unquote(trimChar(val, QUOTEMARK));
const checkContextFreeMode = (name: string, isClosingTag?: boolean) => {
if (contextFreeTag !== '' && isClosingTag) {
contextFreeTag = '';
@@ -339,8 +341,16 @@ export function createLexer(buffer: string, options: LexerOptions = {}): LexerTo
function isTokenNested(token: Token) {
const value = openTag + SLASH + token.getValue();
// potential bottleneck
return buffer.indexOf(value) > -1;
if (nestedMap.has(value)) {
return !!nestedMap.get(value);
} else {
const status = (buffer.indexOf(value) > -1)
nestedMap.set(value, status);
return status;
}
}
return {
+3 -19
View File
@@ -1,3 +1,5 @@
import type { NodeContent, TagNodeTree, LexerTokenizer, ParseOptions } from "@bbob/types";
import {
CLOSE_BRAKET,
OPEN_BRAKET,
@@ -7,26 +9,8 @@ import {
import { createLexer } from "./lexer";
import type { NodeContent, TagNodeTree } from "@bbob/plugin-helper";
import type { LexerTokenizer, LexerOptions } from "./types";
import type { Token } from "./Token";
type ParseError = {
tagName: string;
lineNumber: number;
columnNumber: number;
};
export interface ParseOptions {
createTokenizer?: (input: string, options?: LexerOptions) => LexerTokenizer;
openTag?: string;
closeTag?: string;
onlyAllowTags?: string[];
contextFreeTags?: string[];
enableEscapeTags?: boolean;
onError?: (error: ParseError) => void;
}
class NodeList<Value> {
private n: Value[];
@@ -201,7 +185,7 @@ function parse(input: string, opts: ParseOptions = {}) {
function handleTagStart(token: Token) {
flushTagNodes();
const tagNode = TagNode.create(token.getValue());
const tagNode = TagNode.create(token.getValue(), {}, []);
const isNested = isTokenNested(token);
tagNodes.push(tagNode);
-15
View File
@@ -1,15 +0,0 @@
import type Token from "./Token";
export interface LexerTokenizer {
tokenize: () => Token<string>[];
isTokenNested?: (token: Token<string>) => boolean;
}
export type LexerOptions = {
openTag?: string;
closeTag?: string;
onlyAllowTags?: string[];
enableEscapeTags?: boolean;
contextFreeTags?: string[];
onToken?: (token?: Token<string>) => void;
};
+9 -1
View File
@@ -35,6 +35,10 @@ export class CharGrabber {
}
getCurr() {
if (typeof this.s[this.c.pos] === 'undefined') {
return ''
}
return this.s[this.c.pos]
}
@@ -51,7 +55,11 @@ export class CharGrabber {
getPrev() {
const prevPos = this.c.pos - 1;
return typeof this.s[prevPos] !== 'undefined' ? this.s[prevPos] : null;
if (typeof this.s[prevPos] === 'undefined') {
return null
}
return this.s[prevPos];
}
isLast() {
+3
View File
@@ -20,6 +20,9 @@
"browser": "dist/index.js",
"browserName": "BbobPluginHelper",
"types": "types/index.d.ts",
"dependencies": {
"@bbob/types": "*"
},
"exports": {
".": {
"types": "./types/index.d.ts",
+3 -3
View File
@@ -1,3 +1,5 @@
import type { NodeContent, TagNodeObject, TagNodeTree } from "@bbob/types";
import { OPEN_BRAKET, CLOSE_BRAKET, SLASH } from './char';
import {
getUniqAttr,
@@ -8,8 +10,6 @@ import {
isTagNode,
} from './helpers';
import type { NodeContent, TagNodeObject, TagNodeTree } from "./types";
const getTagAttrs = <AttrValue>(tag: string, params: Record<string, AttrValue>) => {
const uniqAttr = getUniqAttr(params);
@@ -105,7 +105,7 @@ export class TagNode implements TagNodeObject {
return `${tagStart}${content}${this.toTagEnd({ openTag, closeTag })}`;
}
static create(tag: string, attrs: Record<string, unknown> = {}, content: TagNodeTree = []) {
static create(tag: string, attrs: Record<string, unknown> = {}, content: TagNodeTree = null) {
return new TagNode(tag, attrs, content)
}
+9 -8
View File
@@ -1,6 +1,7 @@
import type { NodeContent, StringNode } from "@bbob/types";
import { N } from './char';
import type { TagNode } from "./TagNode";
import type { NodeContent, StringNode } from "./types";
function isTagNode(el: unknown): el is TagNode {
return typeof el === 'object' && el !== null && 'tag' in el;
@@ -15,10 +16,10 @@ function isEOL(el: string) {
return el === N
}
function keysReduce<Res, Def extends Res, T extends Record<string, unknown>>(obj: T, reduce: (acc: Def, key: keyof T) => Res, def: Def): Res {
function keysReduce<Res, Def extends Res, T extends Record<string, unknown>>(obj: T, reduce: (acc: Def, key: keyof T, obj: T) => Res, def: Def): Res {
const keys = Object.keys(obj)
return keys.reduce((acc, key) => reduce(acc, key), def)
return keys.reduce((acc, key) => reduce(acc, key, obj), def)
}
function getNodeLength(node: NodeContent): number {
@@ -85,7 +86,7 @@ function attrValue<AttrValue = unknown>(name: string, value: AttrValue) {
* @example
* attrsToString({ 'foo': true, 'bar': bar' }) => 'foo="true" bar="bar"'
*/
function attrsToString<AttrValue = unknown>(values: Record<string, AttrValue> | null) {
function attrsToString<AttrValue = unknown>(values?: Record<string, AttrValue> | null) {
// To avoid some malformed attributes
if (values == null) {
return '';
@@ -93,7 +94,7 @@ function attrsToString<AttrValue = unknown>(values: Record<string, AttrValue> |
return keysReduce(
values,
(arr, key) => [...arr, attrValue(key, values[key])],
(arr, key, obj) => [...arr, attrValue(key, obj[key])],
[''],
).join(' ');
}
@@ -103,10 +104,10 @@ function attrsToString<AttrValue = unknown>(values: Record<string, AttrValue> |
* @example
* getUniqAttr({ 'foo': true, 'bar': bar' }) => 'bar'
*/
function getUniqAttr<Value>(attrs: Record<string, Value>) {
function getUniqAttr<Value>(attrs?: Record<string, Value>) {
return keysReduce(
attrs,
(res, key) => (attrs[key] === key ? attrs[key] : null),
attrs || {},
(res, key, obj) => (obj[key] === key ? obj[key] : null),
null,
)
}
-1
View File
@@ -1,4 +1,3 @@
export * from "./helpers";
export * from "./char";
export * from "./TagNode";
export * from "./types";
@@ -44,6 +44,18 @@ describe('@bbob/plugin-helper/TagNode', () => {
expect(newTagNode.content).toEqual(tagNode.content);
});
test('null content', () => {
const tagNode = TagNode.create('img');
expect(String(tagNode)).toBe('[img]');
});
test('array content', () => {
const tagNode = TagNode.create('img', {}, []);
expect(String(tagNode)).toBe('[img]');
});
describe('toString', () => {
test('tag with content and params', () => {
const tagNode = TagNode.create('test', {test: 1}, ['Hello']);
+2 -1
View File
@@ -9,7 +9,8 @@
],
"dependencies": {
"@bbob/plugin-helper": "*",
"@bbob/preset": "*"
"@bbob/preset": "*",
"@bbob/types": "*"
},
"devDependencies": {
"@bbob/core": "*",
+85 -97
View File
@@ -4,18 +4,18 @@ import {
isStringNode,
isTagNode,
TagNode,
TagNodeTree,
} from "@bbob/plugin-helper";
import type { NodeContent, TagNodeObject } from "@bbob/plugin-helper";
import type { PresetTagsDefinition } from "@bbob/preset";
import type { BbobPluginOptions } from "@bbob/core";
import type { BBobPluginOptions, PresetTagsDefinition, NodeContent, TagNodeTree, TagNodeObject } from "@bbob/types";
const isStartsWith = (node: string, type: string) => node[0] === type;
const getStyleFromAttrs = (attrs: Record<string, unknown>) => {
return Object.keys(attrs)
const styleAttrs = (attrs?: Record<string, unknown>) => {
const values = attrs || {}
return Object.keys(values)
.reduce<string[]>((acc, key: "color" | "size") => {
const value = attrs[key];
const value = values[key];
if (typeof value === "string") {
if (key === "color") {
@@ -32,53 +32,49 @@ const getStyleFromAttrs = (attrs: Record<string, unknown>) => {
.join(" ");
};
const asListItems = (content: TagNodeTree): NodeContent[] => {
let listIdx = 0;
const listItems = [] as Array<NodeContent>;
export const toListNodes = (content?: TagNodeTree) => {
if (content && Array.isArray(content)) {
return content.reduce<NodeContent[]>((acc, node) => {
const listItem = acc[acc.length - 1];
const createItemNode = () => TagNode.create("li");
const ensureListItem = (val: NodeContent) => {
listItems[listIdx] = listItems[listIdx] || val;
};
const addItem = (val: NodeContent) => {
const listItem = listItems[listIdx];
// *Entry
if (isStringNode(node) && isStartsWith(String(node), "*")) {
// from '*Entry' to 'Entry'
const content = String(node).slice(1)
if (listItem && isTagNode(listItem) && Array.isArray(listItem.content)) {
listItem.content = listItem.content.concat(val);
}
// else if (Array.isArray(listItem) && Array.isArray(listItems[listIdx])) {
// listItems[listIdx] = listItems[listIdx].concat(val);
// }
};
acc.push(TagNode.create("li", {}, [content]));
if (Array.isArray(content)) {
content.forEach((el) => {
if (isStringNode(el) && isStartsWith(String(el), "*")) {
if (listItems[listIdx]) {
listIdx++;
}
ensureListItem(createItemNode());
addItem(String(el).substr(1));
} else if (isTagNode(el) && TagNode.isOf(el, "*")) {
if (listItems[listIdx]) {
listIdx++;
}
ensureListItem(createItemNode());
} else if (!isTagNode(listItems[listIdx])) {
listIdx++;
ensureListItem(el);
} else if (listItems[listIdx]) {
addItem(el);
} else {
ensureListItem(el);
return acc
}
});
// { tag: '*', attrs: {}, content: [] }
if (isTagNode(node) && TagNode.isOf(node, "*")) {
acc.push(TagNode.create("li", {}, []));
return acc
}
if (!isTagNode(listItem)) {
acc.push(node);
return acc
}
if (listItem && isTagNode(listItem) && Array.isArray(listItem.content)) {
listItem.content = listItem.content.concat(node);
return acc
}
acc.push(node);
return acc
}, []);
}
return listItems;
return content
};
const renderUrl = (node: TagNodeObject, render: BbobPluginOptions["render"]) =>
const renderUrl = (node: TagNodeObject, render: BBobPluginOptions["render"]) =>
getUniqAttr(node.attrs)
? getUniqAttr(node.attrs)
: render(node.content || []);
@@ -86,61 +82,53 @@ const renderUrl = (node: TagNodeObject, render: BbobPluginOptions["render"]) =>
const toNode = (
tag: string,
attrs: Record<string, unknown>,
content: TagNodeTree
content?: TagNodeTree
) => TagNode.create(tag, attrs, content);
const toStyle = (style: string) => ({ style });
const defaultTags: PresetTagsDefinition<
| "b"
| "i"
| "u"
| "s"
| "url"
| "img"
| "quote"
| "code"
| "style"
| "list"
| "color"
> = {
b: (node) => toNode("span", toStyle("font-weight: bold;"), node.content),
i: (node) => toNode("span", toStyle("font-style: italic;"), node.content),
u: (node) =>
toNode("span", toStyle("text-decoration: underline;"), node.content),
s: (node) =>
toNode("span", toStyle("text-decoration: line-through;"), node.content),
url: (node, { render }) =>
toNode(
"a",
{
href: renderUrl(node, render),
},
node.content
),
img: (node, { render }) =>
toNode(
"img",
{
src: render(node.content),
},
null
),
quote: (node) => toNode("blockquote", {}, [toNode("p", {}, node.content)]),
code: (node) => toNode("pre", {}, node.content),
style: (node) =>
toNode("span", toStyle(getStyleFromAttrs(node.attrs)), node.content),
list: (node) => {
const type = getUniqAttr(node.attrs);
export const defineStyleNode = (tag: string, style: string) => (node: TagNodeObject) => toNode(tag, toStyle(style), node.content)
return toNode(
type ? "ol" : "ul",
type ? { type } : {},
asListItems(node.content)
);
},
color: (node) =>
toNode("span", toStyle(`color: ${getUniqAttr(node.attrs)};`), node.content),
};
export const defaultTags = (function createTags() {
const tags: PresetTagsDefinition<string> = {
b: defineStyleNode("span", "font-weight: bold;"),
i: defineStyleNode("span", "font-style: italic;"),
u: defineStyleNode("span", "text-decoration: underline;"),
s: defineStyleNode("span", "text-decoration: line-through;"),
url: (node, { render }) =>
toNode(
"a",
{
href: renderUrl(node, render),
},
node.content
),
img: (node, { render }) =>
toNode(
"img",
{
src: render(node.content),
},
null
),
quote: (node) => toNode("blockquote", {}, [toNode("p", {}, node.content)]),
code: (node) => toNode("pre", {}, node.content),
style: (node) =>
toNode("span", toStyle(styleAttrs(node.attrs)), node.content),
list: (node) => {
const type = getUniqAttr(node.attrs);
return toNode(
type ? "ol" : "ul",
type ? { type } : {},
toListNodes(node.content)
);
},
color: (node) =>
toNode("span", toStyle(`color: ${getUniqAttr(node.attrs)};`), node.content),
}
return tags
})();
export default defaultTags;
+1 -4
View File
@@ -9,10 +9,7 @@
],
"dependencies": {
"@bbob/preset-html5": "*",
"@bbob/preset": "*"
},
"devDependencies": {
"@bbob/core": "*"
"@bbob/types": "*"
},
"main": "lib/index.js",
"module": "es/index.js",
+4 -2
View File
@@ -1,5 +1,5 @@
import presetHTML5 from '@bbob/preset-html5';
import type { PresetTagsDefinition } from '@bbob/preset';
import type { PresetTagsDefinition } from '@bbob/types';
const tagAttr = (style: Record<string, string>) => ({
attrs: {
@@ -7,7 +7,7 @@ const tagAttr = (style: Record<string, string>) => ({
},
});
export default presetHTML5.extend((tags: PresetTagsDefinition<'b' | 'i' | 'u' | 's'>) => ({
const presetReact = presetHTML5.extend((tags: PresetTagsDefinition<'b' | 'i' | 'u' | 's'>) => ({
...tags,
b: (...args) => ({
@@ -30,3 +30,5 @@ export default presetHTML5.extend((tags: PresetTagsDefinition<'b' | 'i' | 'u' |
...tagAttr({ textDecoration: 'line-through' }),
}),
}));
export default presetReact;
+1 -4
View File
@@ -9,10 +9,7 @@
],
"dependencies": {
"@bbob/preset-html5": "*",
"@bbob/preset": "*"
},
"devDependencies": {
"@bbob/core": "*"
"@bbob/types": "*"
},
"main": "lib/index.js",
"module": "es/index.js",
+27 -20
View File
@@ -1,5 +1,6 @@
import presetHTML5 from '@bbob/preset-html5';
import type { PresetTagsDefinition } from '@bbob/preset';
import type { PresetTagsDefinition } from '@bbob/types';
export const tagAttr = (style: Record<string, string>) => ({
attrs: {
@@ -7,29 +8,35 @@ export const tagAttr = (style: Record<string, string>) => ({
},
});
export const createTags = (tags: PresetTagsDefinition<'b' | 'i' | 'u' | 's'>) => ({
b: (...args) => ({
...tags.b(...args),
...tagAttr({ fontWeight: 'bold' }),
}),
export const createTags = (tags: PresetTagsDefinition<string>) => {
const newTags: PresetTagsDefinition<string> = {
b: (...args) => ({
...tags.b?.(...args),
...tagAttr({ fontWeight: 'bold' }),
}),
i: (...args) => ({
...tags.i(...args),
...tagAttr({ fontStyle: 'italic' }),
}),
i: (...args) => ({
...tags.i?.(...args),
...tagAttr({ fontStyle: 'italic' }),
}),
u: (...args) => ({
...tags.u(...args),
...tagAttr({ textDecoration: 'underline' }),
}),
u: (...args) => ({
...tags.u?.(...args),
...tagAttr({ textDecoration: 'underline' }),
}),
s: (...args) => ({
...tags.s(...args),
...tagAttr({ textDecoration: 'line-through' }),
}),
} as PresetTagsDefinition);
s: (...args) => ({
...tags.s?.(...args),
...tagAttr({ textDecoration: 'line-through' }),
}),
}
export default presetHTML5.extend((tags) => ({
return newTags
};
const presetVue = presetHTML5.extend((tags: PresetTagsDefinition<string>) => ({
...tags,
...createTags(tags),
}));
export default presetVue;
+14 -9
View File
@@ -1,23 +1,28 @@
import type { PresetTagFunction } from "@bbob/types";
import preset, { createTags, tagAttr } from '../src'
const tagFactory = (tag: string): PresetTagFunction => jest.fn((...args) => ({ tag }))
const createTag = (tag: string, style: Record<string, string>) => ({ tag, ...tagAttr(style)})
describe('@bbob/preset-vue', () => {
test('is a function', () => {
expect(preset).toBeInstanceOf(Function)
})
test('createTags', () => {
const defFn = jest.fn(() => ({}))
const defTags = {
b: defFn,
i: defFn,
u: defFn,
s: defFn,
b: tagFactory('b'),
i: tagFactory('i'),
u: tagFactory('u'),
s: tagFactory('s'),
}
const tags = createTags(defTags)
const args = [{tag: 'test'}]
expect(tags.b()).toEqual(tagAttr({ fontWeight: 'bold' }))
expect(tags.i()).toEqual(tagAttr({ fontStyle: 'italic' }))
expect(tags.u()).toEqual(tagAttr({ textDecoration: 'underline' }))
expect(tags.s()).toEqual(tagAttr({ textDecoration: 'line-through' }))
expect(tags.b?.({tag: 'b'}, ...args)).toEqual(createTag('b',{ fontWeight: 'bold' }))
expect(tags.i?.({tag: 'i'}, ...args)).toEqual(createTag('i',{ fontStyle: 'italic' }))
expect(tags.u?.({tag: 'u'}, ...args)).toEqual(createTag('u',{ textDecoration: 'underline' }))
expect(tags.s?.({tag: 's'}, ...args)).toEqual(createTag('s',{ textDecoration: 'line-through' }))
})
});
+3
View File
@@ -16,6 +16,9 @@
],
"dependencies": {
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},
"devDependencies": {
"@bbob/core": "*"
},
"main": "lib/index.js",
-1
View File
@@ -1,3 +1,2 @@
export { default } from "./preset";
export * from "./preset";
export * from "./types";
+26 -50
View File
@@ -1,87 +1,63 @@
import { isTagNode } from "@bbob/plugin-helper";
import type {
BBobCoreTagNodeTree,
BbobPluginOptions,
BBobPluginFunction,
} from "@bbob/core";
import { isTagNode } from "@bbob/plugin-helper";
import type {
BBobPluginOptions,
PresetExtendCallback,
PresetFactoryOptions,
PresetFactory,
PresetOptions,
PresetTagsDefinition,
} from "./types";
ProcessorFunction
} from "@bbob/types";
function process<Name extends string = string>(
tags: PresetTagsDefinition<Name>,
export function process<Tags extends PresetTagsDefinition = PresetTagsDefinition, Options extends PresetOptions = PresetOptions>(
tags: Tags,
tree: BBobCoreTagNodeTree,
core: BbobPluginOptions,
options: PresetFactoryOptions = {}
core: BBobPluginOptions,
options: Options
) {
return tree.walk((node) => {
if (isTagNode(node) && typeof tags[node.tag] === "function") {
if (isTagNode(node)) {
const tag = node.tag;
const tagCallback = tags[tag];
return tagCallback(node, core, options);
if (typeof tagCallback === "function") {
return tagCallback(node, core, options);
}
}
return node;
});
}
export type ProcessorFunction = typeof process;
export type ProcessorReturnType = ReturnType<ProcessorFunction>;
export interface PresetExecutor<
TagName extends string = string,
AttrValue = unknown
> extends BBobPluginFunction {
(tree: BBobCoreTagNodeTree, core?: BbobPluginOptions): ProcessorReturnType;
options: PresetOptions;
}
export interface PresetFactory<
TagName extends string = string,
AttrValue = unknown,
Names extends string = string
> {
(opts?: PresetOptions): PresetExecutor;
options?: PresetOptions;
extend: (
cb: PresetExtendCallback<Names>
) => PresetFactory<TagName, AttrValue, Names>;
}
/**
* Create a preset plugin for @bbob/core
*/
function createPreset<Names extends string = string>(
defTags: PresetTagsDefinition<Names>,
processor: ProcessorFunction = process
function createPreset<Tags extends PresetTagsDefinition = PresetTagsDefinition, RootOptions extends PresetOptions = PresetOptions,>(
defTags: Tags,
processor: ProcessorFunction<Tags> = process
) {
const presetFactory: PresetFactory = (opts: PresetOptions = {}) => {
const presetFactory: PresetFactory<typeof defTags, RootOptions> = <Options extends RootOptions>(opts?: Options) => {
presetFactory.options = Object.assign(presetFactory.options || {}, opts);
function presetExecutor(
tree: BBobCoreTagNodeTree,
core: BbobPluginOptions
core: BBobPluginOptions
) {
return processor(defTags, tree, core, presetFactory.options);
return processor(defTags, tree, core, presetFactory.options || {});
}
presetExecutor.options = presetFactory.options;
presetExecutor.options = presetFactory.options as Options;
return presetExecutor;
};
presetFactory.extend = function presetExtend<ExtendNames extends string>(
callback: PresetExtendCallback<Names & ExtendNames>
presetFactory.extend = function presetExtend<NewTags extends PresetTagsDefinition = PresetTagsDefinition>(
callback: PresetExtendCallback<Tags, NewTags, RootOptions>
) {
return createPreset(
callback(defTags, presetFactory.options || {}),
processor
);
const newTags = callback(defTags, presetFactory.options)
return createPreset<typeof newTags, RootOptions>(newTags, processor as unknown as ProcessorFunction<NewTags>);
};
return presetFactory;
-15
View File
@@ -1,15 +0,0 @@
import type { TagNodeObject } from "@bbob/plugin-helper";
import type { BbobPluginOptions } from "@bbob/core";
export type PresetFactoryOptions = Record<string, unknown>
export type PresetTagFunction<Node extends object = TagNodeObject> = (
node: Node,
core: BbobPluginOptions,
options: PresetFactoryOptions
) => Node
export type PresetTagsDefinition<Name extends string = string> = Record<Name | string, PresetTagFunction>
export type PresetOptions = Record<string, unknown>
export type PresetExtendCallback<Names extends string> = (defTags: PresetTagsDefinition<Names>, options: PresetOptions) => PresetTagsDefinition<Names>
+9 -8
View File
@@ -2,21 +2,22 @@ import { createPreset, PresetTagsDefinition } from '../src';
import { BBobCoreOptions, createTree } from '@bbob/core'
describe('@bbob/preset', () => {
const presetFactory = (defTags: PresetTagsDefinition) => {
const presetFactory = <Tags extends PresetTagsDefinition = PresetTagsDefinition>(defTags: Tags) => {
const processor = jest.fn((tags, tree, core, options) => tags)
const preset = createPreset<Tags>(defTags, processor)
return {
preset: createPreset(defTags, processor),
preset,
processor,
core: {} as BBobCoreOptions
}
}
test('create', () => {
const defTags = { test: () => 'test' }
const defTags = { test: () => ({ tag: 'test' }) }
const options = { foo: 'bar' }
const tree = createTree([], {})
const { preset, processor, core } = presetFactory(defTags);
const { preset, processor } = presetFactory(defTags);
expect(preset.extend)
.toBeDefined();
@@ -28,8 +29,8 @@ describe('@bbob/preset', () => {
expect(processor.mock.calls.length).toBe(1);
});
test('extend', () => {
const defTags = { foo: () => 'foo' }
const extendedTags = { bar: () => 'bar' }
const defTags = { foo: () => ({ tag: 'foo'}) }
const extendedTags = { bar: () =>({tag: 'bar'}) }
const options = { foo: 'bar' }
const tree = createTree([], {})
const { preset, processor, core } = presetFactory(defTags);
@@ -47,8 +48,8 @@ describe('@bbob/preset', () => {
expect(processor.mock.calls.length).toBe(1);
});
test('pass options', () => {
const { preset, processor } = presetFactory({ test: () => 'test' });
const newPreset = preset.extend((tags, options) => ({ bar: () => 'bar' }));
const { preset } = presetFactory({ test: () => ({tag: 'test'}) });
const newPreset = preset.extend((tags, options) => ({ bar: () => ({tag: 'bar'}) }));
const instance = preset({ foo: 'bar' });
const instance2 = newPreset({ some: 'some' });
+2 -1
View File
@@ -11,7 +11,8 @@
"dependencies": {
"@bbob/core": "*",
"@bbob/html": "*",
"@bbob/plugin-helper": "*"
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},
"peerDependencies": {
"react": "> 15.0"
+7 -2
View File
@@ -1,8 +1,13 @@
import React, { ReactNode } from 'react';
import type { BBobPlugins, BBobCoreOptions } from '@bbob/core';
import type { BBobPlugins, BBobCoreOptions } from '@bbob/types';
import { render } from './render';
const content = (children: ReactNode, plugins?: BBobPlugins, options?: BBobCoreOptions) => React.Children.map(children, (child) => (typeof child === 'string' ? render(child, plugins, options) : child));
const content = (children: ReactNode, plugins?: BBobPlugins, options?: BBobCoreOptions) =>
React.Children.map(children,
(child) =>
(typeof child === 'string' ? render(child, plugins, options) : child)
);
export type BBobReactComponentProps = {
children: ReactNode
+10 -8
View File
@@ -1,20 +1,22 @@
/* eslint-disable no-use-before-define */
import React, { ReactNode } from "react";
import { render as htmlrender } from "@bbob/html";
import core, {
BBobCoreOptions,
BBobCoreTagNodeTree,
BBobPlugins,
} from "@bbob/core";
import core from "@bbob/core";
import {
isTagNode,
isStringNode,
isEOL,
TagNode,
TagNodeTree,
} from "@bbob/plugin-helper";
import type {
BBobCoreOptions,
BBobCoreTagNodeTree,
BBobPlugins,
TagNodeTree,
} from "@bbob/types";
const toAST = (
source: string,
plugins?: BBobPlugins,
@@ -45,8 +47,8 @@ function tagToReactElement(node: TagNode, index: number) {
);
}
function renderToReactNodes(nodes: BBobCoreTagNodeTree | TagNodeTree) {
if (Array.isArray(nodes) && nodes.length) {
function renderToReactNodes(nodes?: BBobCoreTagNodeTree | TagNodeTree) {
if (nodes && Array.isArray(nodes) && nodes.length) {
return nodes.reduce<ReactNode[]>((arr, node, index) => {
if (isTagNode(node)) {
arr.push(tagToReactElement(node, index));
+4
View File
@@ -0,0 +1,4 @@
dist
es
lib
test
+8
View File
@@ -0,0 +1,8 @@
coverage
dist
lib
es
types
test/*.d.ts
test/*.map
tsconfig.tsbuildinfo
+7
View File
@@ -0,0 +1,7 @@
pnpm-lock.yaml
coverage
src
!dist
!lib
!es
*.test.js
+34
View File
@@ -0,0 +1,34 @@
{
"name": "@bbob/types",
"version": "3.0.2",
"description": "Shared Typescript types of @bbob",
"keywords": [
"bbcode",
"types"
],
"files": [
"dist",
"lib",
"src",
"es",
"types"
],
"types": "types/index.d.ts",
"module": "types/index.d.ts",
"homepage": "https://github.com/JiLiZART/bbob",
"author": "Nikolay Kostyurin <jilizart@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/JiLiZART/bbob/issues"
},
"repository": {
"type": "git",
"url": "git://github.com/JiLiZART/bbob.git"
},
"scripts": {
"types": "pkg-task"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
}
}
+54
View File
@@ -0,0 +1,54 @@
import { ParseOptions } from "./parser";
import { NodeContent, PartialNodeContent, TagNodeObject, TagNodeTree } from "./types";
export interface BBobCoreOptions<
Data = unknown | null,
Options extends ParseOptions = ParseOptions
> extends ParseOptions {
skipParse?: boolean;
parser?: (source: string, options?: Options) => TagNodeObject[];
render?: (ast?: TagNodeTree, options?: Options) => string;
data?: Data;
}
export type IterateCallback<Content> = (node: Content) => Content
export interface BBobPluginOptions<
Options extends ParseOptions = ParseOptions,
> {
parse: BBobCoreOptions["parser"];
render: (ast?: TagNodeTree, options?: Options) => string;
iterate: <Content, Iterable = ArrayLike<Content> | Content>(t: Iterable, cb: IterateCallback<Content>) => Iterable;
data: unknown | null;
}
export interface BBobPluginFunction {
(tree: BBobCoreTagNodeTree, options: BBobPluginOptions): BBobCoreTagNodeTree;
}
export interface BBobCore<
InputValue = string | TagNodeObject[],
Options extends BBobCoreOptions = BBobCoreOptions
> {
process(
input: InputValue,
opts?: Options
): {
readonly html: string;
tree: BBobCoreTagNodeTree;
raw: TagNodeObject[] | string;
messages: unknown[];
};
}
export interface BBobCoreTagNodeTree extends Array<NodeContent> {
messages: unknown[];
options: BBobCoreOptions;
walk: (cb: IterateCallback<NodeContent>) => BBobCoreTagNodeTree;
match: (
expression: PartialNodeContent | PartialNodeContent[],
cb: IterateCallback<NodeContent>
) => BBobCoreTagNodeTree;
}
export type BBobPlugins = BBobPluginFunction | BBobPluginFunction[];
+4
View File
@@ -0,0 +1,4 @@
export * from './types'
export * from './parser'
export * from './core'
export * from './preset'
+44
View File
@@ -0,0 +1,44 @@
import { TagNodeTree } from "./types";
export interface ParseError {
tagName: string;
lineNumber: number;
columnNumber: number;
}
export interface TagNode {
readonly tag: string
attrs?: Record<string, unknown>
content?: TagNodeTree
}
export interface Token<TokenValue = string> {
readonly t: number // type
readonly v: string // value
readonly l: number // line
readonly r: number // row
}
export interface LexerTokenizer {
tokenize: () => Token<string>[];
isTokenNested?: (token: Token<string>) => boolean;
}
export interface LexerOptions {
openTag?: string;
closeTag?: string;
onlyAllowTags?: string[];
enableEscapeTags?: boolean;
contextFreeTags?: string[];
onToken?: (token?: Token<string>) => void;
}
export interface ParseOptions {
createTokenizer?: (input: string, options?: LexerOptions) => LexerTokenizer;
openTag?: string;
closeTag?: string;
onlyAllowTags?: string[];
contextFreeTags?: string[];
enableEscapeTags?: boolean;
onError?: (error: ParseError) => void;
}
+46
View File
@@ -0,0 +1,46 @@
import { BBobCoreTagNodeTree, BBobPluginFunction, BBobPluginOptions } from "./core";
import { TagNodeObject } from "./types";
export type PartialRecord<K extends keyof any, T> = Partial<Record<K, T>>
export type PresetTagsDefinition<Key extends string = string> = Record<Key, PresetTagFunction>
export type PresetOptions = Record<string, unknown>
export type ProcessorFunction<Tags extends PresetTagsDefinition = PresetTagsDefinition, Options extends PresetOptions = PresetOptions> = (
tags: Tags,
tree: BBobCoreTagNodeTree,
core: BBobPluginOptions,
options: Options
) => BBobCoreTagNodeTree
// export type ProcessorReturnType = ReturnType<ProcessorFunction>;
export interface PresetTagFunction<Node extends TagNodeObject = TagNodeObject, Options extends PresetOptions = PresetOptions> {
(
node: Node,
data: BBobPluginOptions,
options: Options
): Node
}
export interface PresetExtendCallback<Tags, NewTags = Tags, Options extends PresetOptions = PresetOptions> {
(defTags: Tags, options?: Options): NewTags
}
export interface PresetExecutor<Options extends PresetOptions = PresetOptions> extends BBobPluginFunction {
(tree: BBobCoreTagNodeTree, core?: BBobPluginOptions): BBobCoreTagNodeTree;
options: Options;
}
export interface PresetFactory<
Tags extends PresetTagsDefinition = PresetTagsDefinition,
RootOptions extends PresetOptions = PresetOptions,
> {
<Options extends RootOptions>(opts?: Options): PresetExecutor<Options>;
options?: RootOptions;
extend: <NewTags extends PresetTagsDefinition = PresetTagsDefinition>(
cb: PresetExtendCallback<Tags, NewTags, RootOptions>
) => PresetFactory<NewTags, RootOptions>;
}
@@ -2,8 +2,8 @@ export type StringNode = string | number
export interface TagNodeObject {
readonly tag: string
attrs: Record<string, unknown>
content: TagNodeTree
attrs?: Record<string, unknown>
content?: TagNodeTree
}
export type NodeContent = TagNodeObject | StringNode | null
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"outDir": "./types"
},
"include": [
"./src/**/*"
]
}
+2 -1
View File
@@ -11,7 +11,8 @@
"dependencies": {
"@bbob/core": "*",
"@bbob/html": "*",
"@bbob/plugin-helper": "*"
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},
"peerDependencies": {
"vue": "2.x"
+1 -1
View File
@@ -1,7 +1,7 @@
import { defineComponent } from 'vue';
import type { BBobCoreOptions, BBobPlugins } from '@bbob/types';
import { render } from './render';
import type { BBobCoreOptions, BBobPlugins } from '@bbob/core';
export type BBobVueComponentProps = {
container: string
+17 -17
View File
@@ -1,36 +1,36 @@
/* eslint-disable no-use-before-define,import/prefer-default-export */
import core, { BBobPlugins, BBobCoreOptions } from '@bbob/core';
import core from '@bbob/core';
import * as html from '@bbob/html';
import { isStringNode, isTagNode } from '@bbob/plugin-helper';
import type { TagNodeTree, TagNode } from "@bbob/plugin-helper";
import type { TagNodeTree, TagNode, BBobPlugins, BBobCoreOptions } from '@bbob/types';
import type { CreateElement, VNodeChildrenArrayContents } from 'vue';
import type { StyleValue } from 'vue/types/jsx';
const toAST = (source: string, plugins: BBobPlugins = [], options: BBobCoreOptions = {}) => core(plugins)
.process(source, {
...options,
render: (input) => html.render(input, { stripTags: true }),
}).tree;
.process(source, {
...options,
render: (input) => html.render(input, { stripTags: true }),
}).tree;
const isContentEmpty = (content: TagNodeTree) => (!content || Array.isArray(content) && content?.length === 0);
const isContentEmpty = (content?: TagNodeTree) => (!content || Array.isArray(content) && content?.length === 0);
function tagToVueNode(createElement: CreateElement, node: TagNode, index: number) {
const { class: className, style, ...domProps } = node.attrs || {};
return createElement(
node.tag,
{
key: index,
class: className,
style: style as StyleValue,
domProps,
},
isContentEmpty(node.content) ? null : renderToVueNodes(createElement, node.content),
node.tag,
{
key: index,
class: className,
style: style as StyleValue,
domProps,
},
isContentEmpty(node.content) ? null : renderToVueNodes(createElement, node.content),
);
}
function renderToVueNodes(createElement: CreateElement, nodes: TagNodeTree) {
function renderToVueNodes(createElement: CreateElement, nodes?: TagNodeTree) {
if (Array.isArray(nodes)) {
return nodes.reduce((arr, node, index) => {
if (isTagNode(node)) {
@@ -38,7 +38,7 @@ function renderToVueNodes(createElement: CreateElement, nodes: TagNodeTree) {
} else if (isStringNode(node)) {
arr.push(String(node));
}
return arr;
}, [] as VNodeChildrenArrayContents);
}
+2 -1
View File
@@ -11,7 +11,8 @@
"dependencies": {
"@bbob/core": "*",
"@bbob/html": "*",
"@bbob/plugin-helper": "*"
"@bbob/plugin-helper": "*",
"@bbob/types": "*"
},
"peerDependencies": {
"vue": "3.x"
+1 -1
View File
@@ -1,7 +1,7 @@
import { defineComponent, h, VNode } from "vue";
import { render } from "./render";
import type { BBobPlugins, BBobCoreOptions } from "@bbob/core";
import type { BBobPlugins, BBobCoreOptions } from "@bbob/types";
type VueComponentProps = {
container: string;
+3 -2
View File
@@ -1,11 +1,12 @@
/* eslint-disable no-use-before-define,import/prefer-default-export */
import core, { BBobCoreOptions, BBobPlugins } from "@bbob/core";
import core from "@bbob/core";
import * as html from "@bbob/html";
import { h, VNodeArrayChildren } from "vue";
import type { BBobCoreOptions, BBobPlugins, TagNodeTree } from "@bbob/types";
import {
TagNode,
TagNodeTree,
isStringNode,
isTagNode,
} from "@bbob/plugin-helper";
+70 -22
View File
@@ -160,6 +160,9 @@ importers:
benchmark:
specifier: 2.1.4
version: 2.1.4
cpupro:
specifier: '*'
version: 0.5.0
picocolors:
specifier: 1.0.0
version: 1.0.0
@@ -216,6 +219,9 @@ importers:
'@bbob/plugin-helper':
specifier: '*'
version: link:../bbob-plugin-helper
'@bbob/types':
specifier: '*'
version: link:../bbob-types
packages/bbob-html:
dependencies:
@@ -225,23 +231,37 @@ importers:
'@bbob/plugin-helper':
specifier: '*'
version: link:../bbob-plugin-helper
'@bbob/types':
specifier: '*'
version: link:../bbob-types
packages/bbob-parser:
dependencies:
'@bbob/plugin-helper':
specifier: '*'
version: link:../bbob-plugin-helper
'@bbob/types':
specifier: '*'
version: link:../bbob-types
packages/bbob-plugin-helper: {}
packages/bbob-plugin-helper:
dependencies:
'@bbob/types':
specifier: '*'
version: link:../bbob-types
packages/bbob-preset:
dependencies:
'@bbob/core':
specifier: '*'
version: link:../bbob-core
'@bbob/plugin-helper':
specifier: '*'
version: link:../bbob-plugin-helper
'@bbob/types':
specifier: '*'
version: link:../bbob-types
devDependencies:
'@bbob/core':
specifier: '*'
version: link:../bbob-core
packages/bbob-preset-html5:
dependencies:
@@ -251,6 +271,9 @@ importers:
'@bbob/preset':
specifier: '*'
version: link:../bbob-preset
'@bbob/types':
specifier: '*'
version: link:../bbob-types
devDependencies:
'@bbob/core':
specifier: '*'
@@ -261,29 +284,21 @@ importers:
packages/bbob-preset-react:
dependencies:
'@bbob/preset':
specifier: '*'
version: link:../bbob-preset
'@bbob/preset-html5':
specifier: '*'
version: link:../bbob-preset-html5
devDependencies:
'@bbob/core':
'@bbob/types':
specifier: '*'
version: link:../bbob-core
version: link:../bbob-types
packages/bbob-preset-vue:
dependencies:
'@bbob/preset':
specifier: '*'
version: link:../bbob-preset
'@bbob/preset-html5':
specifier: '*'
version: link:../bbob-preset-html5
devDependencies:
'@bbob/core':
'@bbob/types':
specifier: '*'
version: link:../bbob-core
version: link:../bbob-types
packages/bbob-react:
dependencies:
@@ -296,6 +311,9 @@ importers:
'@bbob/plugin-helper':
specifier: '*'
version: link:../bbob-plugin-helper
'@bbob/types':
specifier: '*'
version: link:../bbob-types
devDependencies:
'@bbob/preset-react':
specifier: ^3.0.2
@@ -316,6 +334,8 @@ importers:
specifier: 18.x
version: 18.2.0(react@18.2.0)
packages/bbob-types: {}
packages/bbob-vue2:
dependencies:
'@bbob/core':
@@ -327,6 +347,9 @@ importers:
'@bbob/plugin-helper':
specifier: '*'
version: link:../bbob-plugin-helper
'@bbob/types':
specifier: '*'
version: link:../bbob-types
devDependencies:
'@bbob/preset-vue':
specifier: '*'
@@ -352,6 +375,9 @@ importers:
'@bbob/plugin-helper':
specifier: '*'
version: link:../bbob-plugin-helper
'@bbob/types':
specifier: '*'
version: link:../bbob-types
devDependencies:
'@bbob/preset-vue':
specifier: '*'
@@ -2191,7 +2217,6 @@ packages:
/@discoveryjs/json-ext@0.5.7:
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
engines: {node: '>=10.0.0'}
dev: true
/@endemolshinegroup/cosmiconfig-typescript-loader@3.0.2(cosmiconfig@7.1.0)(typescript@4.9.5):
resolution: {integrity: sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==}
@@ -5777,7 +5802,6 @@ packages:
/ansi-colors@4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
dev: true
/ansi-escapes@3.2.0:
resolution: {integrity: sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==}
@@ -6650,6 +6674,13 @@ packages:
resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==}
dev: true
/clap@3.1.1:
resolution: {integrity: sha512-vp42956Ax06WwaaheYEqEOgXZ3VKJxgccZ0gJL0HpyiupkIS9RVJFo5eDU1BPeQAOqz+cclndZg4DCqG1sJReQ==}
engines: {node: ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
dependencies:
ansi-colors: 4.1.3
dev: false
/clean-css@5.3.3:
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
engines: {node: '>= 10.0'}
@@ -7326,6 +7357,16 @@ packages:
typescript: 5.1.6
dev: true
/cpupro@0.5.0:
resolution: {integrity: sha512-NEoLapQrQwrSrEBj5c9vxyUHSYiUv2aGOJ3EuO8g0j5zc7rxdNzzvT1PPY7G1H2guXBQrziHUvgdg8NkZYGMeA==}
hasBin: true
dependencies:
'@discoveryjs/json-ext': 0.5.7
clap: 3.1.1
open: 8.4.2
v8-profiler-next: 1.5.1
dev: false
/create-jest@29.7.0(@types/node@20.4.5):
resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -7819,7 +7860,6 @@ packages:
/define-lazy-prop@2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
engines: {node: '>=8'}
dev: true
/define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
@@ -10173,7 +10213,6 @@ packages:
resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
engines: {node: '>=8'}
hasBin: true
dev: true
/is-extendable@0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
@@ -10419,7 +10458,6 @@ packages:
engines: {node: '>=8'}
dependencies:
is-docker: 2.2.1
dev: true
/isarray@1.0.0:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
@@ -12081,6 +12119,10 @@ packages:
thenify-all: 1.6.0
dev: true
/nan@2.19.0:
resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==}
dev: false
/nanoid@3.3.6:
resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -12653,7 +12695,6 @@ packages:
define-lazy-prop: 2.0.0
is-docker: 2.2.1
is-wsl: 2.2.0
dev: true
/opener@1.5.2:
resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
@@ -15994,6 +16035,13 @@ packages:
resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==}
dev: true
/v8-profiler-next@1.5.1:
resolution: {integrity: sha512-7gnfJ3x7zN3gzmVs69OvJBNze5dLCIeY2Necy+IzomWmprSCRsBbCn5GfwAJHkWJxzoex3gyRexxvYGlgR93yg==}
requiresBuild: true
dependencies:
nan: 2.19.0
dev: false
/v8-to-istanbul@9.1.3:
resolution: {integrity: sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==}
engines: {node: '>=10.12.0'}
+1
View File
@@ -6,6 +6,7 @@
"dom.iterable",
"esnext"
],
"baseUrl": ".",
"checkJs": false,
"skipLibCheck": true,
"strict": true,