npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ts-series/factories

v1.1.0

Published

A lightweight TypeScript DSL for generating HTML, SVG and MathML server-side without a template engine.

Readme

Factories.ts

Factories.ts is a lightweight library which provides a domain-specific language (DSL) for coding markup directly in TypeScript to generate HTML, but also SVG and MathML on the server side.

Installation

Available on JSR for Deno, and on npm for Node.js.

deno add jsr:@ts-series/factories
npm install @ts-series/factories

Import path is identical for both runtimes:

import { html, head, body } from "@ts-series/factories"

Usage

Instead of a separate template language with its own engine, the HTML structure can be built dynamically using ordinary JavaScript functions:

import {
	body, br, div, head, html, p, title
} from '@ts-series/factories'


let page = html({lang: "de"},
    head(
        title("Kafka Blindtext")
    ),
    body(
        p("Aber sie überwanden sich, umdrängten den Käfig und wollten sich gar nicht fortrühren. Jemand musste Josef K. verleumdet haben, denn ohne dass er etwas Böses getan hätte, wurde er eines Morgens verhaftet.")
    )
);

console.log(page.expand());

Besides significantly better performance, this approach also allows direct use of JavaScript/TypeScript for the decision logic within the markup.

Elements

Apart from the var element as variable, all HTML elements and attributes are available under their actual names as ordinary functions: Nesting their calls builds the HTML declaratively. This approach is not only much more efficient than running a separate text processing engine, but also eliminates the need to learn a template language with its own syntax.

Another intention behind Factories.ts is to provide a DSL with as little syntactical noise as possible: Void elements such as br or elements without attributes and content do not even have to be called as functions, but can be passed directly:

let hello = p("Hallo,", br, "kaputte Welt!");

In fact, all non-void elements have a rest parameter, so they can contain any number of other elements or JavaScript values. Arguments that do not represent HTML elements and are not already strings get automatically converted. Therefore, by overriding the corresponding toString method, the output in HTML can be precisely defined. This is particularly useful for outputting specific data, without any additional abstraction layers needed.

Attributes

Any attribute can be specified using an object whose keys are interpreted as such, and gets passed as the first argument; or specified subsequently using the set method. In addition, there are same-named methods for all global and element-specific HTML attributes, for example x.id("about").

If an attribute has the value null, it is simply translated into HTML without a value representing Boolean attributes such as checked.

Another special feature offers the attribute class, to which an array of class names is assignable instead of concatenating them first.

String Expansion

The problem with the template approach is that it can only link markup with the backend programming language through detours such as an additional template language, which raises the question of why these two things should be separated in the first place. In Factories.ts, conversion to an HTML string using the expand method only happens at the very end, right before the response is sent:

import { serve } from "hono"
import { html, head, title, body, p } from "@ts-series/factories"

serve((req) => {
    const page = html({lang: "en"},
        head(title("Hello")),
        body(p("Hello, World!"))
    );

    return new Response(page.expand(), {
        headers: { "Content-Type": "text/html" }
    });
});

Post-Construction Manipulation

Until string expansion, inner elements and other content are held in plain arrays, which is not only quite efficient since no complex virtual DOM is involved, but also allows for modifications after the initial construction:

const page = div(p("Hello"));
page.append(p("World"));
page.insertAt(0, p("First"));

However, such post-construction manipulation is not actually required, since markup can be assembled programmatically in advance through conditionals. Nonetheless, this capability is offered for edge cases.

API Reference

A complete list of available methods can be found in the Reference.

Changelog

See CHANGELOG.md for version history.

Internals

Exceptions are not thrown. Instead, necessary type conversions get performed to enable error-free expansion into valid HTML as far as possible, regardless of what values are passed.

Development Status

Factories.ts contains fewer than 2,000 lines of code with no dependencies. The principle of how HTML is described in JavaScript is quite logical and so are the interfaces. Consequently, no breaks are to be expected in future versions.

Future versions are only intended to offer more methods, provided this seems sensible. The question that still needs to be clarified here is whether more type safety should be built in, which ensures that, for example, the href can only be called on those elements that are allowed to contain it according to the current HTML5 specification. Currently, no distinction is made here for the sake of simplicity, as well as to accommodate custom elements.

License

This software is published under the Unlicense.