diff --git a/lib/nodes.d.ts b/lib/nodes.d.ts index 4d0e114..f054efd 100644 --- a/lib/nodes.d.ts +++ b/lib/nodes.d.ts @@ -1,22 +1,21 @@ -import { Nilable } from "./lang.js"; +import { Nil, Nilable } from "./lang.js"; export declare type AnyNode = AnySyncNode | AnyAsyncNode; export declare type AnyAsyncNode = Promise; -export declare type AnySyncNode = TextNode | Elem | Frag; +export declare type AnySyncNode = TextNode | Elem | Frag | Nil | false; export declare class TextNode extends String { } -export declare function F(children: AnyNode[]): Frag; +export declare function F(...children: AnyNode[]): Frag; export declare class Frag { #private; constructor(); get children(): Nilable; withText(text: string): this; addText(text: string): void; - maybeWithChildren(nodes?: Nilable): this; withChildren(nodes: AnyNode[]): this; withChild(node: AnyNode): this; addChild(node: AnyNode): void; } -export declare function E(tagName: string, attrs: ElemAttrs, children?: Nilable): Elem; +export declare function E(tagName: string, attrs: ElemAttrs, ...children: AnyNode[]): Elem; export declare type ElemAttrs = Record; export declare class Elem extends Frag { #private; diff --git a/lib/nodes.mjs b/lib/nodes.mjs index 8c695bd..1492569 100644 --- a/lib/nodes.mjs +++ b/lib/nodes.mjs @@ -1,7 +1,7 @@ import { isNil } from "./lang.mjs"; export class TextNode extends String { } -export function F(children) { +export function F(...children) { return new Frag().withChildren(children); } export class Frag { @@ -19,11 +19,6 @@ export class Frag { addText(text) { this.addChild(new TextNode(text)); } - maybeWithChildren(nodes) { - if (isNil(nodes)) - return this; - return this.withChildren(nodes); - } withChildren(nodes) { nodes.forEach((n) => this.addChild(n)); return this; @@ -38,8 +33,8 @@ export class Frag { this.#children.push(node); } } -export function E(tagName, attrs, children) { - return new Elem(tagName).withAttrs(attrs).maybeWithChildren(children); +export function E(tagName, attrs, ...children) { + return new Elem(tagName).withAttrs(attrs).withChildren(children); } export class Elem extends Frag { #tagName; diff --git a/lib/str.mjs b/lib/str.mjs index c39c0d7..11b2dda 100644 --- a/lib/str.mjs +++ b/lib/str.mjs @@ -7,9 +7,11 @@ export class StrRenderer { } async function encodeAnyNode(node) { const syncNode = await node; - return syncNode instanceof TextNode - ? encodeTextNode(syncNode) - : encodeNode(syncNode); + return !syncNode + ? null + : syncNode instanceof TextNode + ? encodeTextNode(syncNode) + : encodeNode(syncNode); } function encodeTextNode(node) { return String(node); @@ -17,7 +19,7 @@ function encodeTextNode(node) { async function encodeNode(node) { const encodedChildren = isNil(node.children) ? 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 ? encodeHtmlElement(node.tagName, node.attrs, encodedChildren) : encodeHtmlFragment(encodedChildren); diff --git a/src/nodes.mts b/src/nodes.mts index ec5ff8b..6ed2927 100644 --- a/src/nodes.mts +++ b/src/nodes.mts @@ -1,12 +1,12 @@ -import { isNil, Nilable } from "./lang.mjs"; +import { isNil, Nil, Nilable } from "./lang.mjs"; export type AnyNode = AnySyncNode | AnyAsyncNode; export type AnyAsyncNode = Promise; -export type AnySyncNode = TextNode | Elem | Frag; +export type AnySyncNode = TextNode | Elem | Frag | Nil | false; export class TextNode extends String {} -export function F(children: AnyNode[]): Frag { +export function F(...children: AnyNode[]): Frag { return new Frag().withChildren(children); } @@ -30,11 +30,6 @@ export class Frag { this.addChild(new TextNode(text)); } - maybeWithChildren(nodes?: Nilable): this { - if (isNil(nodes)) return this; - return this.withChildren(nodes); - } - withChildren(nodes: AnyNode[]): this { nodes.forEach((n) => this.addChild(n)); return this; @@ -54,9 +49,9 @@ export class Frag { export function E( tagName: string, attrs: ElemAttrs, - children?: Nilable + ...children: AnyNode[] ): Elem { - return new Elem(tagName).withAttrs(attrs).maybeWithChildren(children); + return new Elem(tagName).withAttrs(attrs).withChildren(children); } export type ElemAttrs = Record; diff --git a/src/str.mts b/src/str.mts index dd0a1c4..448f09c 100644 --- a/src/str.mts +++ b/src/str.mts @@ -8,9 +8,11 @@ export class StrRenderer implements Renderer { } } -async function encodeAnyNode(node: AnyNode): Promise { +async function encodeAnyNode(node: AnyNode): Promise> { const syncNode = await node; - return syncNode instanceof TextNode + return !syncNode + ? null + : syncNode instanceof TextNode ? encodeTextNode(syncNode) : encodeNode(syncNode); } @@ -22,7 +24,9 @@ function encodeTextNode(node: TextNode): string { async function encodeNode(node: Elem | Frag): Promise { const encodedChildren = isNil(node.children) ? 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 ? encodeHtmlElement(node.tagName, node.attrs, encodedChildren) : encodeHtmlFragment(encodedChildren);