feat: improve api

This commit is contained in:
Dmitriy Pleshevskiy 2022-03-20 23:22:43 +03:00
parent f7d94d9010
commit 1b21c2d796
8 changed files with 101 additions and 61 deletions

2
lib/lang.d.ts vendored
View File

@ -3,3 +3,5 @@ export declare type Nullable<T> = T | null;
export declare type Nilable<T> = T | Nil;
export declare type Nil = null | undefined;
export declare function isBool(v: unknown): v is boolean;
export declare function isStr(v: unknown): v is string;
export declare function intoArr<T>(v: T | T[]): T[];

View File

@ -4,3 +4,9 @@ export function isNil(v) {
export function isBool(v) {
return typeof v === "boolean";
}
export function isStr(v) {
return typeof v === "string";
}
export function intoArr(v) {
return Array.isArray(v) ? v : [v];
}

20
lib/nodes.d.ts vendored
View File

@ -1,26 +1,28 @@
import { Nil, Nilable } from "./lang.js";
export declare type AnyNode = TextNode | Elem | Frag | Nil | false;
export declare class TextNode extends String {
}
export declare function Et(tagName: string, ...texts: string[]): Elem;
export declare function Ea(tagName: string, attrs?: ElemAttrs, children?: AnyNode | AnyNode[]): Elem;
export declare function E(tagName: string, children: AnyNode | AnyNode[]): Elem;
export declare function F(...children: AnyNode[]): Frag;
export declare type AnyNode = TextNode | Elem | Frag | Nil | false;
export declare type TextNode = string;
export declare class Frag {
#private;
constructor();
get children(): Nilable<AnyNode[]>;
withText(text: string): this;
addText(text: string): void;
withChildren(...nodes: AnyNode[]): this;
withText(texts: TextNode | TextNode[]): this;
addText(texts: TextNode | TextNode[]): void;
withChildren(nodes: AnyNode | AnyNode[]): this;
addChildren(nodes: AnyNode | AnyNode[]): void;
addChild(node: AnyNode): void;
}
export declare function E(tagName: string, attrs: ElemAttrs, ...children: AnyNode[]): Elem;
export declare type ElemAttrs = Record<string, unknown>;
export declare class Elem extends Frag {
#private;
constructor(tagName: string);
get tagName(): string;
get attrs(): Record<string, unknown>;
withAttrs(attrs: Record<string, unknown>): Elem;
withAttr(name: string, value: unknown): Elem;
withAttrs(attrs: ElemAttrs): Elem;
addAttrs(attrs: ElemAttrs): void;
addAttr(name: string, value: unknown): void;
addChild(node: AnyNode): void;
}

View File

@ -1,8 +1,20 @@
import { isNil } from "./lang.mjs";
export class TextNode extends String {
import { intoArr, isNil } from "./lang.mjs";
export function Et(tagName, ...texts) {
return new Elem(tagName).withText(texts);
}
export function Ea(tagName, attrs, children) {
const el = new Elem(tagName);
if (attrs)
el.addAttrs(attrs);
if (children)
el.addChildren(children);
return el;
}
export function E(tagName, children) {
return new Elem(tagName).withChildren(children);
}
export function F(...children) {
return new Frag().withChildren(...children);
return new Frag().withChildren(children);
}
export class Frag {
#children;
@ -12,26 +24,28 @@ export class Frag {
get children() {
return this.#children;
}
withText(text) {
this.addText(text);
withText(texts) {
this.addText(texts);
return this;
}
addText(text) {
this.addChild(new TextNode(text));
addText(texts) {
this.addChildren(intoArr(texts)
.map((t) => t.trim())
.join(" "));
}
withChildren(...nodes) {
nodes.forEach((n) => this.addChild(n));
withChildren(nodes) {
this.addChildren(nodes);
return this;
}
addChildren(nodes) {
intoArr(nodes).forEach((n) => this.addChild(n));
}
addChild(node) {
if (isNil(this.#children))
this.#children = [];
this.#children.push(node);
}
}
export function E(tagName, attrs, ...children) {
return new Elem(tagName).withAttrs(attrs).withChildren(...children);
}
export class Elem extends Frag {
#tagName;
#attrs;
@ -49,12 +63,11 @@ export class Elem extends Frag {
return this.#attrs;
}
withAttrs(attrs) {
Object.entries(attrs).forEach(([key, value]) => this.addAttr(key, value));
this.addAttrs(attrs);
return this;
}
withAttr(name, value) {
this.addAttr(name, value);
return this;
addAttrs(attrs) {
Object.entries(attrs).forEach(([key, value]) => this.addAttr(key, value));
}
addAttr(name, value) {
this.#attrs[name] = value;

View File

@ -1,16 +1,12 @@
import { isBool, isNil } from "./lang.mjs";
import { Elem, TextNode } from "./nodes.mjs";
import { isBool, isNil, isStr } from "./lang.mjs";
import { Elem } from "./nodes.mjs";
export class StrRenderer {
render(node) {
return encodeNode(node);
}
}
function encodeAnyNode(node) {
return !node
? null
: node instanceof TextNode
? encodeTextNode(node)
: encodeNode(node);
return !node ? null : isStr(node) ? encodeTextNode(node) : encodeNode(node);
}
function encodeTextNode(node) {
return String(node);

View File

@ -11,3 +11,11 @@ export type Nil = null | undefined;
export function isBool(v: unknown): v is boolean {
return typeof v === "boolean";
}
export function isStr(v: unknown): v is string {
return typeof v === "string";
}
export function intoArr<T>(v: T | T[]): T[] {
return Array.isArray(v) ? v : [v];
}

View File

@ -1,13 +1,31 @@
import { isNil, Nil, Nilable } from "./lang.mjs";
import { intoArr, isNil, Nil, Nilable } from "./lang.mjs";
export type AnyNode = TextNode | Elem | Frag | Nil | false;
export function Et(tagName: string, ...texts: string[]): Elem {
return new Elem(tagName).withText(texts);
}
export class TextNode extends String {}
export function Ea(
tagName: string,
attrs?: ElemAttrs,
children?: AnyNode | AnyNode[]
): Elem {
const el = new Elem(tagName);
if (attrs) el.addAttrs(attrs);
if (children) el.addChildren(children);
return el;
}
export function E(tagName: string, children: AnyNode | AnyNode[]): Elem {
return new Elem(tagName).withChildren(children);
}
export function F(...children: AnyNode[]): Frag {
return new Frag().withChildren(...children);
return new Frag().withChildren(children);
}
export type AnyNode = TextNode | Elem | Frag | Nil | false;
export type TextNode = string;
export class Frag {
#children: Nilable<AnyNode[]>;
@ -19,34 +37,34 @@ export class Frag {
return this.#children;
}
withText(text: string): this {
this.addText(text);
withText(texts: TextNode | TextNode[]): this {
this.addText(texts);
return this;
}
addText(text: string): void {
this.addChild(new TextNode(text));
addText(texts: TextNode | TextNode[]): void {
this.addChildren(
intoArr(texts)
.map((t) => t.trim())
.join(" ")
);
}
withChildren(...nodes: AnyNode[]): this {
nodes.forEach((n) => this.addChild(n));
withChildren(nodes: AnyNode | AnyNode[]): this {
this.addChildren(nodes);
return this;
}
addChildren(nodes: AnyNode | AnyNode[]): void {
intoArr(nodes).forEach((n) => this.addChild(n));
}
addChild(node: AnyNode): void {
if (isNil(this.#children)) this.#children = [];
this.#children.push(node);
}
}
export function E(
tagName: string,
attrs: ElemAttrs,
...children: AnyNode[]
): Elem {
return new Elem(tagName).withAttrs(attrs).withChildren(...children);
}
export type ElemAttrs = Record<string, unknown>;
export class Elem extends Frag {
@ -69,14 +87,13 @@ export class Elem extends Frag {
return this.#attrs;
}
withAttrs(attrs: Record<string, unknown>): Elem {
Object.entries(attrs).forEach(([key, value]) => this.addAttr(key, value));
withAttrs(attrs: ElemAttrs): Elem {
this.addAttrs(attrs);
return this;
}
withAttr(name: string, value: unknown): Elem {
this.addAttr(name, value);
return this;
addAttrs(attrs: ElemAttrs): void {
Object.entries(attrs).forEach(([key, value]) => this.addAttr(key, value));
}
addAttr(name: string, value: unknown): void {

View File

@ -1,5 +1,5 @@
import { Renderer } from "./types.mjs";
import { isBool, isNil, Nilable, Nullable } from "./lang.mjs";
import { isBool, isNil, isStr, Nilable, Nullable } from "./lang.mjs";
import { AnyNode, Elem, ElemAttrs, Frag, TextNode } from "./nodes.mjs";
export class StrRenderer implements Renderer<string> {
@ -9,11 +9,7 @@ export class StrRenderer implements Renderer<string> {
}
function encodeAnyNode(node: AnyNode): Nullable<string> {
return !node
? null
: node instanceof TextNode
? encodeTextNode(node)
: encodeNode(node);
return !node ? null : isStr(node) ? encodeTextNode(node) : encodeNode(node);
}
function encodeTextNode(node: TextNode): string {