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

feat: typescript support (#185)

* feat: initial typescript support

* feat: typescript support

* feat(plugin-helper): move files to typescript

* chore: update lock files

* feat: preset types

* fix: build

* fix: benchmark

* fix: remove pnpm cache

* fix: bench action

* fix: pnpm recursive install

* fix: nx cache

* fix: lock file

* fix: workflows

* fix: lerna support in pnpm

* fix: pnpm workspace

* fix: remove unused files

* fix: pnpm lock file

* fix: update lerna for support pnpm

* fix: lerna bootstrap

* fix: rollup build

* fix: update nx

* fix: build

* fix: add nx dep target

* fix: remove nx cache

* fix: workflow run on push only for master

* fix: test workflow run on push only for master

* fix: remove parallel for gen types

* fix: benchmark

* fix: benchmark imports

* fix: pnpm

* fix: types errors and pnpm

* fix: types

* fix: types

* refactor: parser

* fix(parser): tests

* fix: preset tests

* fix: react types

* fix: react type declarations

* fix: pnpm lock file

* fix: react preset types

* fix: lock file

* fix: vue2 types

* feat: dev container support

* fix: types

* fix: types

* refactor: rewrite pkg-task, add nx gen-types deps, fix react/render.ts

* refactor: types

* fix: types

* fix: rename gen-types to types

* fix: nx build order

* fix: nx reset

* fix: define nx deps explicit

* fix: build

* fix: nx

* fix: nx order build

* fix: nx deps

* fix: bbob cli tests

* fix: tests

* fix: cli tests and import

* fix: test cover

* fix: cli cover
This commit is contained in:
Nikolay Kost
2024-04-23 21:11:14 +02:00
committed by GitHub
parent 05246b2aea
commit 8797f7f363
149 changed files with 6102 additions and 3670 deletions
+10
View File
@@ -0,0 +1,10 @@
let C1 = 'C1'
let C2 = 'C2'
if (process.env.NODE_ENV !== 'production') {
C1 = '"parser" is not a function, please pass to "process(input, { parser })" right function'
C2 = '"render" function not defined, please pass to "process(input, { render })"'
}
export { C1, C2 }
-62
View File
@@ -1,62 +0,0 @@
import { parse } from '@bbob/parser';
import { iterate, match } from './utils';
function walk(cb) {
return iterate(this, cb);
}
export default function bbob(plugs) {
const plugins = typeof plugs === 'function' ? [plugs] : plugs || [];
let options = {
skipParse: false,
};
return {
process(input, opts) {
options = opts || {};
const parseFn = options.parser || parse;
const renderFn = options.render;
const data = options.data || null;
if (typeof parseFn !== 'function') {
throw new Error('"parser" is not a function, please pass to "process(input, { parser })" right function');
}
let tree = options.skipParse
? input || []
: parseFn(input, options);
// raw tree before modification with plugins
const raw = tree;
tree.messages = [];
tree.options = options;
tree.walk = walk;
tree.match = match;
plugins.forEach((plugin) => {
tree = plugin(tree, {
parse: parseFn,
render: renderFn,
iterate,
match,
data,
}) || tree;
});
return {
get html() {
if (typeof renderFn !== 'function') {
throw new Error('"render" function not defined, please pass to "process(input, { render })"');
}
return renderFn(tree, tree.options);
},
tree,
raw,
messages: tree.messages,
};
},
};
}
+76
View File
@@ -0,0 +1,76 @@
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
extendedTree.messages = [...(extendedTree.messages || [])]
extendedTree.options = {...options, ...extendedTree.options}
extendedTree.walk = function walkNodes(cb: IterateCallback<NodeContent>) {
return iterate(this, cb);
}
extendedTree.match = function matchNodes(expr: PartialNodeContent | PartialNodeContent[], cb: IterateCallback<NodeContent>) {
return match(this, expr, cb)
}
return extendedTree
}
export default function bbob<InputValue = string | NodeContent[], Options extends BBobCoreOptions = BBobCoreOptions>(
plugs?: BBobPlugins
): BBobCore<InputValue, Options> {
const plugins = typeof plugs === 'function' ? [plugs] : plugs || [];
const mockRender = () => ""
return {
process(input, opts) {
const options = opts || { skipParse: false, parser: parse, render: mockRender, data: null } as BBobCoreOptions
const parseFn = options.parser || parse;
const renderFn = options.render;
const data = options.data || null;
if (typeof parseFn !== 'function') {
throw new Error(C1);
}
// raw tree before modification with plugins
const raw = options.skipParse && Array.isArray(input) ? input : parseFn(input as string, options);
let tree = options.skipParse && Array.isArray(input) ? createTree((input || []) as NodeContent[], options) : createTree(raw, options)
for (let idx = 0; idx < plugins.length; idx++) {
const plugin = plugins[idx]
if (typeof plugin === 'function' && renderFn) {
const newTree = plugin(tree, {
parse: parseFn,
render: renderFn,
iterate,
data,
})
tree = createTree(newTree || tree, options)
}
}
return {
get html() {
if (typeof renderFn !== 'function') {
throw new Error(C2);
}
return renderFn(tree, tree.options);
},
tree,
raw,
messages: tree.messages,
};
},
};
}
+57
View File
@@ -0,0 +1,57 @@
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[];
-60
View File
@@ -1,60 +0,0 @@
/* eslint-disable no-plusplus */
const isObj = (value) => (typeof value === 'object');
const isBool = (value) => (typeof value === 'boolean');
export function iterate(t, cb) {
const tree = t;
if (Array.isArray(tree)) {
for (let idx = 0; idx < tree.length; idx++) {
tree[idx] = iterate(cb(tree[idx]), cb);
}
} else if (tree && isObj(tree) && tree.content) {
iterate(tree.content, cb);
}
return tree;
}
export function same(expected, actual) {
if (typeof expected !== typeof actual) {
return false;
}
if (!isObj(expected) || expected === null) {
return expected === actual;
}
if (Array.isArray(expected)) {
return expected.every((exp) => [].some.call(actual, (act) => same(exp, act)));
}
return Object.keys(expected).every((key) => {
const ao = actual[key];
const eo = expected[key];
if (isObj(eo) && eo !== null && ao !== null) {
return same(eo, ao);
}
if (isBool(eo)) {
return eo !== (ao === null);
}
return ao === eo;
});
}
export function match(expression, cb) {
return Array.isArray(expression)
? iterate(this, (node) => {
for (let idx = 0; idx < expression.length; idx++) {
if (same(expression[idx], node)) {
return cb(node);
}
}
return node;
})
: iterate(this, (node) => (same(expression, node) ? cb(node) : node));
}
+72
View File
@@ -0,0 +1,72 @@
/* eslint-disable no-plusplus */
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;
if (Array.isArray(tree)) {
for (let idx = 0; idx < tree.length; idx++) {
tree[idx] = iterate(cb(tree[idx]), cb);
}
} else if (isObj(tree) && 'content' in tree) {
iterate(tree.content, cb);
}
return tree;
}
export function same(expected: unknown, actual: unknown): boolean {
if (typeof expected !== typeof actual) {
return false;
}
if (!isObj(expected) || expected === null) {
return expected === actual;
}
if (Array.isArray(expected)) {
return expected.every((exp) => [].some.call(actual, (act) => same(exp, act)));
}
if (isObj(expected) && isObj(actual)) {
return Object.keys(expected).every((key) => {
const ao = actual[key];
const eo = expected[key];
if (isObj(eo) && isObj(ao)) {
return same(eo, ao);
}
if (isBool(eo)) {
return eo !== (ao === null);
}
return ao === eo;
});
}
return false
}
export function match<Content, Iterable = ArrayLike<Content>>(
t: Iterable,
expression: Content | ArrayLike<Content>,
cb: IterateCallback<Content>
) {
if (Array.isArray(expression)) {
return iterate<Content, Iterable>(t, (node) => {
for (let idx = 0; idx < expression.length; idx++) {
if (same(expression[idx], node)) {
return cb(node);
}
}
return node;
})
}
return iterate<Content, Iterable>(t, (node) => (same(expression, node) ? cb(node) : node));
}