feat: add Nil and false to sync node type
refac: remove maybeWithChildren, use sparse array
This commit is contained in:
parent
9a783eba32
commit
f577128923
5 changed files with 25 additions and 30 deletions
9
lib/nodes.d.ts
vendored
9
lib/nodes.d.ts
vendored
|
@ -1,22 +1,21 @@
|
||||||
import { Nilable } from "./lang.js";
|
import { Nil, Nilable } from "./lang.js";
|
||||||
export declare type AnyNode = AnySyncNode | AnyAsyncNode;
|
export declare type AnyNode = AnySyncNode | AnyAsyncNode;
|
||||||
export declare type AnyAsyncNode = Promise<AnySyncNode>;
|
export declare type AnyAsyncNode = Promise<AnySyncNode>;
|
||||||
export declare type AnySyncNode = TextNode | Elem | Frag;
|
export declare type AnySyncNode = TextNode | Elem | Frag | Nil | false;
|
||||||
export declare class TextNode extends String {
|
export declare class TextNode extends String {
|
||||||
}
|
}
|
||||||
export declare function F(children: AnyNode[]): Frag;
|
export declare function F(...children: AnyNode[]): Frag;
|
||||||
export declare class Frag {
|
export declare class Frag {
|
||||||
#private;
|
#private;
|
||||||
constructor();
|
constructor();
|
||||||
get children(): Nilable<AnyNode[]>;
|
get children(): Nilable<AnyNode[]>;
|
||||||
withText(text: string): this;
|
withText(text: string): this;
|
||||||
addText(text: string): void;
|
addText(text: string): void;
|
||||||
maybeWithChildren(nodes?: Nilable<AnyNode[]>): this;
|
|
||||||
withChildren(nodes: AnyNode[]): this;
|
withChildren(nodes: AnyNode[]): this;
|
||||||
withChild(node: AnyNode): this;
|
withChild(node: AnyNode): this;
|
||||||
addChild(node: AnyNode): void;
|
addChild(node: AnyNode): void;
|
||||||
}
|
}
|
||||||
export declare function E(tagName: string, attrs: ElemAttrs, children?: Nilable<AnyNode[]>): Elem;
|
export declare function E(tagName: string, attrs: ElemAttrs, ...children: AnyNode[]): Elem;
|
||||||
export declare type ElemAttrs = Record<string, unknown>;
|
export declare type ElemAttrs = Record<string, unknown>;
|
||||||
export declare class Elem extends Frag {
|
export declare class Elem extends Frag {
|
||||||
#private;
|
#private;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { isNil } from "./lang.mjs";
|
import { isNil } from "./lang.mjs";
|
||||||
export class TextNode extends String {
|
export class TextNode extends String {
|
||||||
}
|
}
|
||||||
export function F(children) {
|
export function F(...children) {
|
||||||
return new Frag().withChildren(children);
|
return new Frag().withChildren(children);
|
||||||
}
|
}
|
||||||
export class Frag {
|
export class Frag {
|
||||||
|
@ -19,11 +19,6 @@ export class Frag {
|
||||||
addText(text) {
|
addText(text) {
|
||||||
this.addChild(new TextNode(text));
|
this.addChild(new TextNode(text));
|
||||||
}
|
}
|
||||||
maybeWithChildren(nodes) {
|
|
||||||
if (isNil(nodes))
|
|
||||||
return this;
|
|
||||||
return this.withChildren(nodes);
|
|
||||||
}
|
|
||||||
withChildren(nodes) {
|
withChildren(nodes) {
|
||||||
nodes.forEach((n) => this.addChild(n));
|
nodes.forEach((n) => this.addChild(n));
|
||||||
return this;
|
return this;
|
||||||
|
@ -38,8 +33,8 @@ export class Frag {
|
||||||
this.#children.push(node);
|
this.#children.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function E(tagName, attrs, children) {
|
export function E(tagName, attrs, ...children) {
|
||||||
return new Elem(tagName).withAttrs(attrs).maybeWithChildren(children);
|
return new Elem(tagName).withAttrs(attrs).withChildren(children);
|
||||||
}
|
}
|
||||||
export class Elem extends Frag {
|
export class Elem extends Frag {
|
||||||
#tagName;
|
#tagName;
|
||||||
|
|
|
@ -7,7 +7,9 @@ export class StrRenderer {
|
||||||
}
|
}
|
||||||
async function encodeAnyNode(node) {
|
async function encodeAnyNode(node) {
|
||||||
const syncNode = await node;
|
const syncNode = await node;
|
||||||
return syncNode instanceof TextNode
|
return !syncNode
|
||||||
|
? null
|
||||||
|
: syncNode instanceof TextNode
|
||||||
? encodeTextNode(syncNode)
|
? encodeTextNode(syncNode)
|
||||||
: encodeNode(syncNode);
|
: encodeNode(syncNode);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +19,7 @@ function encodeTextNode(node) {
|
||||||
async function encodeNode(node) {
|
async function encodeNode(node) {
|
||||||
const encodedChildren = isNil(node.children)
|
const encodedChildren = isNil(node.children)
|
||||||
? undefined
|
? undefined
|
||||||
: await Promise.all(node.children.map(encodeAnyNode));
|
: await Promise.all(node.children.map(encodeAnyNode)).then((children) => children.filter((c) => Boolean(c)));
|
||||||
return node instanceof Elem
|
return node instanceof Elem
|
||||||
? encodeHtmlElement(node.tagName, node.attrs, encodedChildren)
|
? encodeHtmlElement(node.tagName, node.attrs, encodedChildren)
|
||||||
: encodeHtmlFragment(encodedChildren);
|
: encodeHtmlFragment(encodedChildren);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { isNil, Nilable } from "./lang.mjs";
|
import { isNil, Nil, Nilable } from "./lang.mjs";
|
||||||
|
|
||||||
export type AnyNode = AnySyncNode | AnyAsyncNode;
|
export type AnyNode = AnySyncNode | AnyAsyncNode;
|
||||||
export type AnyAsyncNode = Promise<AnySyncNode>;
|
export type AnyAsyncNode = Promise<AnySyncNode>;
|
||||||
export type AnySyncNode = TextNode | Elem | Frag;
|
export type AnySyncNode = TextNode | Elem | Frag | Nil | false;
|
||||||
|
|
||||||
export class TextNode extends String {}
|
export class TextNode extends String {}
|
||||||
|
|
||||||
export function F(children: AnyNode[]): Frag {
|
export function F(...children: AnyNode[]): Frag {
|
||||||
return new Frag().withChildren(children);
|
return new Frag().withChildren(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,11 +30,6 @@ export class Frag {
|
||||||
this.addChild(new TextNode(text));
|
this.addChild(new TextNode(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
maybeWithChildren(nodes?: Nilable<AnyNode[]>): this {
|
|
||||||
if (isNil(nodes)) return this;
|
|
||||||
return this.withChildren(nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
withChildren(nodes: AnyNode[]): this {
|
withChildren(nodes: AnyNode[]): this {
|
||||||
nodes.forEach((n) => this.addChild(n));
|
nodes.forEach((n) => this.addChild(n));
|
||||||
return this;
|
return this;
|
||||||
|
@ -54,9 +49,9 @@ export class Frag {
|
||||||
export function E(
|
export function E(
|
||||||
tagName: string,
|
tagName: string,
|
||||||
attrs: ElemAttrs,
|
attrs: ElemAttrs,
|
||||||
children?: Nilable<AnyNode[]>
|
...children: AnyNode[]
|
||||||
): Elem {
|
): Elem {
|
||||||
return new Elem(tagName).withAttrs(attrs).maybeWithChildren(children);
|
return new Elem(tagName).withAttrs(attrs).withChildren(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ElemAttrs = Record<string, unknown>;
|
export type ElemAttrs = Record<string, unknown>;
|
||||||
|
|
10
src/str.mts
10
src/str.mts
|
@ -8,9 +8,11 @@ export class StrRenderer implements Renderer<string> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function encodeAnyNode(node: AnyNode): Promise<string> {
|
async function encodeAnyNode(node: AnyNode): Promise<Nullable<string>> {
|
||||||
const syncNode = await node;
|
const syncNode = await node;
|
||||||
return syncNode instanceof TextNode
|
return !syncNode
|
||||||
|
? null
|
||||||
|
: syncNode instanceof TextNode
|
||||||
? encodeTextNode(syncNode)
|
? encodeTextNode(syncNode)
|
||||||
: encodeNode(syncNode);
|
: encodeNode(syncNode);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +24,9 @@ function encodeTextNode(node: TextNode): string {
|
||||||
async function encodeNode(node: Elem | Frag): Promise<string> {
|
async function encodeNode(node: Elem | Frag): Promise<string> {
|
||||||
const encodedChildren = isNil(node.children)
|
const encodedChildren = isNil(node.children)
|
||||||
? undefined
|
? undefined
|
||||||
: await Promise.all(node.children.map(encodeAnyNode));
|
: await Promise.all(node.children.map(encodeAnyNode)).then((children) =>
|
||||||
|
children.filter((c): c is string => Boolean(c))
|
||||||
|
);
|
||||||
return node instanceof Elem
|
return node instanceof Elem
|
||||||
? encodeHtmlElement(node.tagName, node.attrs, encodedChildren)
|
? encodeHtmlElement(node.tagName, node.attrs, encodedChildren)
|
||||||
: encodeHtmlFragment(encodedChildren);
|
: encodeHtmlFragment(encodedChildren);
|
||||||
|
|
Reference in a new issue