element-crafter
Version:
A zero-dependency TypeScript library for creating HTML elements in both SSR and client-side environments
250 lines (249 loc) • 8.52 kB
TypeScript
/**
* Supported attribute value types for HTML elements.
*/
export type AttributeValue = string | number | boolean | null | undefined;
/**
* Event handler function type for DOM events.
*/
export type EventHandler = (event: Event) => void;
/**
* HTML element attributes including event handlers.
*/
export interface Attributes {
[key: string]: AttributeValue | EventHandler;
}
/**
* Content that can be rendered as HTML.
*/
export type RenderableContent = string | number | Node | null | undefined | RenderableContent[];
/**
* Configuration for the HTML builder.
*/
export interface BuilderConfig {
/** Whether to generate SSR-compatible HTML strings */
isSsr: boolean;
/**
* Whether to escape HTML content by default.
*
* @remarks
* - For SSR, set to `true` to escape all content by default (prevents XSS).
* - For client-side, set to `false` if you trust the content source (DOM APIs are safe).
* - Smart escaping: Tags like `script`, `style`, `pre`, `code`, and `textarea` automatically disable escaping regardless of this setting.
* - You can override escaping behavior for specific elements using the `escapeContent` option in `CreateElementOptions`.
* - Always escape user-generated content, but markup, CSS, or JS code is automatically handled correctly.
*/
escapeContent?: boolean;
/** Whether to validate attributes */
validateAttributes?: boolean;
/** Custom void tags (in addition to standard HTML5 void tags) */
customVoidTags?: Set<string>;
}
/**
* Options for creating HTML elements.
*/
export interface CreateElementOptions {
/**
* Whether to escape the content of this specific element.
*
* @remarks
* - Overrides the global `escapeContent` setting for this element.
* - For SSR, set to `false` for elements containing raw HTML, CSS, or JS.
* - For user-generated content, set to `true` to prevent XSS.
* - Note: Tags like `script`, `style`, `pre`, `code`, and `textarea` automatically disable escaping unless explicitly overridden.
*/
escapeContent?: boolean;
/** Whether to validate attributes for this specific element */
validateAttributes?: boolean;
}
/**
* Universal HTML builder for SSR and client-side rendering.
*
* @remarks
* Provides a consistent API for creating HTML elements and managing content
* across different rendering environments. Supports attribute validation,
* content escaping, and performance optimizations.
*
* @example
* ```typescript
* // SSR usage
* const ssrBuilder = new HtmlBuilder({ isSsr: true });
* const html = ssrBuilder.createElement('div', { class: 'container' }, 'Content');
*
* // Client usage
* const clientBuilder = new HtmlBuilder({ isSsr: false });
* const element = clientBuilder.createElement('button', { onclick: handleClick }, 'Click me');
* ```
*/
export declare class HtmlBuilder {
private readonly config;
/** Standard HTML5 void elements */
private static readonly STANDARD_VOID_TAGS;
/** Boolean attributes that don't need values */
private static readonly BOOLEAN_ATTRIBUTES;
/** Tags that typically contain raw content and should not be escaped by default */
private static readonly NO_ESCAPE_TAGS;
/**
* Creates a new HTML builder instance.
*
* @param config - Builder configuration
*/
constructor(config: BuilderConfig);
/**
* Gets whether the builder is in SSR mode.
*/
get isSsr(): boolean;
/**
* Gets all void tags (standard + custom).
*/
private get voidTags();
/**
* Escapes HTML content to prevent XSS attacks.
*
* @param content - Content to escape
* @returns Escaped content
*/
static escapeHtml(content: unknown): string;
/**
* Determines whether content should be escaped based on tag name and explicit options.
*
* @param tagName - HTML tag name
* @param explicitEscape - Explicit escape option from CreateElementOptions
* @returns Whether content should be escaped
*
* @remarks
* This method implements smart tag-based auto-escaping:
* - Explicit options always take precedence
* - Tags like script, style, pre, code automatically disable escaping
* - Other tags use the global escapeContent setting
*/
private shouldEscapeContent;
/**
* Validates attribute name and value.
*
* @param name - Attribute name.
* @param value - Attribute value.
* @throws {TypeError} If the attribute name is invalid.
* @throws {DOMException} If the attribute value is potentially unsafe.
*/
private validateAttribute;
/**
* Builds attribute string for SSR.
*
* @param attributes - Element attributes
* @returns Formatted attribute string
*/
private buildAttributeString;
/**
* Flattens nested content arrays.
*
* @param content - Content to flatten
* @returns Flattened content array
*/
private flattenContent;
/**
* Processes content for rendering.
*
* @param content - Raw content
* @param escapeContent - Whether to escape content
* @returns Processed content string
*/
private processContent;
/**
* Creates an HTML element.
*
* @param tagName - HTML tag name
* @param attributes - Element attributes
* @param options - Creation options
* @param children - Child content
* @returns DOM element or HTML string
*/
createElement<K extends keyof HTMLElementTagNameMap>(tagName: K, attributes?: Attributes, options?: CreateElementOptions, ...children: RenderableContent[]): HTMLElementTagNameMap[K] | string;
/**
* Creates an element for SSR (returns HTML string).
*/
private createElementSSR;
/**
* Creates an element for client-side (returns DOM element).
*/
private createElementClient;
/**
* Creates a text node or text content.
*
* @param text - Text content
* @param escape - Whether to escape the text
* @returns Text node or escaped string
*/
createText(text: string, escape?: boolean): Text | string | {
__escaped: true;
value: string;
};
/**
* Creates a document fragment or concatenated HTML.
*
* @param children - Child content
* @returns Document fragment or HTML string
*/
createFragment(...children: RenderableContent[]): DocumentFragment | string;
}
/**
* Page builder utilities for creating complete HTML documents.
*
* @remarks
* Provides utilities for building complete HTML pages with proper structure,
* meta tags, and content integration.
*/
export declare class PageBuilder {
/**
* Builds a complete HTML page with proper document structure.
*
* @param options - Page configuration options
* @returns Complete HTML document string
*
* @example
* ```typescript
* const html = PageBuilder.buildPage({
* title: 'My App',
* head: '<meta name="description" content="My awesome app">',
* body: '<div class="app">Hello World</div>',
* scripts: '<script src="/app.js"></script>'
* });
* ```
*/
static buildPage(options: {
title: string;
head?: string;
body: string;
scripts?: string;
lang?: string;
charset?: string;
}): string;
/**
* Builds an HTML page using template replacement.
*
* @param templateContent - The HTML template content with placeholders
* @param replacements - Object containing placeholder replacements
* @returns Processed HTML string
*
* @example
* ```typescript
* const html = PageBuilder.buildFromTemplate(templateHtml, {
* '{{TITLE}}': 'My App',
* '{{CONTENT}}': '<div>Hello World</div>'
* });
* ```
*/
static buildFromTemplate(templateContent: string, replacements: Record<string, string>): string;
}
/**
* Creates a new HTML builder instance.
*/
export declare function createHtmlBuilder(config: BuilderConfig): HtmlBuilder;
/**
* Creates an HTML builder configured for server-side rendering.
*/
export declare function createSSRBuilder(options?: Omit<BuilderConfig, "isSsr">): HtmlBuilder;
/**
* Creates an HTML builder configured for client-side rendering.
*/
export declare function createClientBuilder(options?: Omit<BuilderConfig, "isSsr">): HtmlBuilder;
export default HtmlBuilder;