Skip to content

Improve root README.md with comprehensive monorepo documentation #14

@EthanThatOneKid

Description

@EthanThatOneKid

Improve root README.md with comprehensive monorepo documentation

Based on a thorough review of the entire repository, here is what an optimal root README.md would look like for FartLabs/ht:


FartLabs/ht

Ask DeepWiki

JSR @fartlabs/ht

JSR @fartlabs/htx

GitHub Actions

A monorepo hosting two complementary, type-safe HTML rendering packages for Deno and TypeScript:

Package Description Style
@fartlabs/ht Type-safe HTML string rendering — no JSX required Lowercase functions: div({}, "hello")
@fartlabs/htx JSX rendering powered by @fartlabs/jsonx Uppercase JSX components: <DIV>hello</DIV>

Both packages cover HTML, SVG, and MathML elements. Typings are auto-generated from @mdn/browser-compat-data, including deprecated/experimental markers. All element functions return plain HTML strings — no virtual DOM, no runtime overhead.


Packages

@fartlabs/ht — Plain TypeScript

Type-safe, zero-runtime-dependency HTML string builder. Each HTML/SVG/MathML element is a TypeScript function that accepts typed props and optional string children and returns a string.

Install:

deno add jsr:@fartlabs/ht

Quick start:

import { a, div, h1, p } from "@fartlabs/ht";

const page = div(
  { id: "app" },
  h1({}, "Hello"),
  p({}, "See ", a({ href: "https://jsr.io/@fartlabs/ht" }, "@fartlabs/ht")),
);

// <div id="app"><h1>Hello</h1><p>See <a href="...">@fartlabs/ht</a></p></div>

SVG example:

import { circle, svg } from "@fartlabs/ht/svg";

const icon = svg(
  { width: "100", height: "100" },
  circle({ cx: "50", cy: "50", r: "40", fill: "yellow" }),
);

MathML example:

import { math, mi, mo, msup } from "@fartlabs/ht/mathml";

const formula = math({}, msup({}, mi({}, "x"), mi({}, "2")), mo({}, "+"), mi({}, "y"));

// <math><msup><mi>x</mi><mi>2</mi></msup><mo>+</mo><mi>y</mi></math>

Full docs → packages/ht/README.md and https://jsr.io/@fartlabs/ht


@fartlabs/htx — JSX

Write JSX that renders directly to HTML strings. Components are the UPPERCASE versions of HTML tag names (e.g. DIV, H1, INPUT). Powered by @fartlabs/jsonx.

Install:

deno add jsr:@fartlabs/htx

Configure JSX in deno.json:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@fartlabs/htx"
  }
}

Quick start (main.tsx):

import { A, BODY, H1, P } from "@fartlabs/htx";

const html = (
  <BODY>
    <H1>Hello, World!</H1>
    <P>See <A href="https://jsr.io/@fartlabs/htx">@fartlabs/htx</A></P>
  </BODY>
);

Deno.writeTextFileSync("index.html", html);

Custom components:

import { DIV, H1, P } from "@fartlabs/htx";

type GreetProps = { name: string; messages: string[] };

function Greet({ name, messages }: GreetProps) {
  return (
    <DIV>
      <H1>Hello, {name}!</H1>
      {messages.map((m) => <P>{m}</P>).join("")}
    </DIV>
  );
}

Full docs → packages/htx/README.md and https://jsr.io/@fartlabs/htx


Repository structure

FartLabs/ht/
├── generate.ts               # Centralized code generation script for both packages
├── packages/
│   ├── ht/                   # @fartlabs/ht — plain TypeScript API
│   │   ├── deno.json
│   │   ├── README.md
│   │   └── src/
│   │       ├── render.ts             # renderElement, renderAttrs, renderStyle
│   │       ├── global_attributes.ts  # GlobalAttributes, DataAttributes (generated)
│   │       ├── mod.ts / html.ts / svg.ts / mathml.ts  (generated)
│   │       └── elements/html|svg|mathml/  (generated per-element files)
│   └── htx/                  # @fartlabs/htx — JSX API
│       ├── deno.json
│       ├── README.md
│       └── src/
│           ├── render.ts             # Re-exports @fartlabs/ht/render
│           ├── jsx-runtime.ts        # Re-exports @fartlabs/jsonx/jsx-runtime
│           ├── global_attributes.ts  (generated, adds children prop)
│           ├── mod.ts / html.ts / svg.ts / mathml.ts  (generated)
│           └── elements/html|svg|mathml/  (generated per-element files)
└── .github/workflows/
    └── weekly.yaml           # Auto-update BCD, regenerate, bump patch versions

Key differences between @fartlabs/ht and @fartlabs/htx

@fartlabs/ht @fartlabs/htx
API style div({class:"x"}, "child") <DIV class="x">child</DIV>
Function naming lowercase (a, div, h1) UPPERCASE (A, DIV, H1)
Children Rest parameters ...children: string[] children prop or rest parameters
JSX runtime None @fartlabs/jsonx
Props type imports Re-exported from own package Imported from @fartlabs/ht

Code generation

All files under packages/*/src/elements/ and packages/*/src/global_attributes.ts are auto-generated. Do not edit them directly.

To regenerate both packages from the latest MDN Browser Compatibility Data:

deno task generate

A weekly CI job (.github/workflows/weekly.yaml) automatically updates the @mdn/browser-compat-data dependency, regenerates both packages, runs tests, and bumps the patch version of both packages/ht/deno.json and packages/htx/deno.json when data changes.


Contributing

deno fmt       # Format code
deno lint      # Lint code
deno test      # Run tests
deno task generate  # Regenerate element files from MDN BCD

If you change generation logic in generate.ts, run deno task generate and commit the resulting file changes.

See individual package READMEs for package-specific notes:


License

  • @fartlabs/ht — MIT License
  • @fartlabs/htx — WTFPL

Developed with ❤️ @FartLabs


Notes

  • The repository has no root deno.json visible in the file tree (only deno.lock and generate.ts at root), so the root README is purely documentation — it does not serve as a Deno workspace config. A root deno.json would be the natural companion if workspace support were added.

  • The generate.ts file is the single source of truth for both packages. Any changes to element generation must go through it.

  • @fartlabs/htx does not have its own JSX runtime implementation — it delegates entirely to @fartlabs/jsonx via re-export in jsx-runtime.ts.

  • The @fartlabs/htx package has a separate README (packages/htx/README.md) that still references the old @fartlabs/htx JSR badge URL and GitHub Actions URL from the original standalone repo — these should be updated to point to the monorepo URLs once the root README exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions