Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/BaselAshraf81/holystitch/llms.txt

Use this file to discover all available pages before exploring further.

The compiler module (pipeline/compiler.ts) is the core transformation engine of HolyStitch. It takes raw HTML for a single component and outputs valid JSX — renaming attributes, self-closing void elements, converting inline style strings to objects, mapping event handlers to camelCase, and wrapping multi-root fragments. The compiler is entirely regex and string-based. It does not use a full HTML parser, which makes it fast and dependency-light but means complex nesting edge cases are surfaced as warnings in the pipeline output.

compileHTMLToJSX

function compileHTMLToJSX(html: string): string
The main HTML-to-JSX transformer. Accepts a raw HTML string (full document or fragment) and returns a JSX string suitable for use inside a React component’s return statement. Steps applied in order:
  1. Body extraction — strips <!DOCTYPE>, <html>, <head>, and <body> wrappers using extractBodyContent. If a <body> tag is present, its inner content is used; otherwise the full input (minus wrappers) is processed.
  2. Pre-processing — applies two HTML-level fixes before the regex compiler runs (see Pre-processing).
  3. Opening tag transformation — rewrites every opening tag: renames attributes via ATTR_MAP and EVENT_MAP, converts style= strings to objects, self-closes void elements, and passes data-* attributes through unchanged.
  4. Comment conversion — converts HTML comments (<!-- text -->) to JSX comments ({/* text */}).
  5. Fragment wrapping — if the output has more than one root element, wraps the entire result in <>...</>.

Pre-processing

Two patterns are normalised before the regex compiler runs: Material Symbols / Icons — Stitch emits icon names as both a data-icon attribute and as the text content of a <span> with a material-symbols-* or material-icons* class. The Material Symbols font renders the icon purely via the class name; the text content must be empty or the icon name renders as literal text. The pre-processor strips the icon-name text child:
<!-- Input -->
<span class="material-symbols-outlined">check_circle</span>

<!-- After pre-processing -->
<span class="material-symbols-outlined"></span>
<pre><code> blocks — Code examples in Stitch HTML contain raw { and } characters that JSX treats as expression delimiters, causing parse errors. The pre-processor replaces { with &#123; and } with &#125; inside every <pre> block. HTML entities render correctly in the browser.

Attribute reference tables

ATTR_MAP — HTML to JSX attribute renames

HTML attributeJSX attribute
classclassName
forhtmlFor
tabindextabIndex
readonlyreadOnly
maxlengthmaxLength
minlengthminLength
cellpaddingcellPadding
cellspacingcellSpacing
rowspanrowSpan
colspancolSpan
usemapuseMap
frameborderframeBorder
contenteditablecontentEditable
crossorigincrossOrigin
autocompleteautoComplete
autofocusautoFocus
autoplayautoPlay
enctypeencType
formnovalidateformNoValidate
novalidatenoValidate
http-equivhttpEquiv
accesskeyaccessKey
data-* attributes are not in ATTR_MAP and pass through to JSX unchanged — React supports all data-* props natively. Special cases:
  • data-alt is promoted to a proper alt attribute. Stitch uses data-alt on <img> elements instead of the real alt attribute; this transform restores correct accessibility semantics.
  • data-icon is dropped entirely. It is a Stitch artifact for Material Symbols and is redundant with the class-based rendering approach.

EVENT_MAP — HTML event handlers to React props

HTML attributeJSX prop
onclickonClick
ondblclickonDoubleClick
onchangeonChange
oninputonInput
onsubmitonSubmit
onresetonReset
onfocusonFocus
onbluronBlur
onkeydownonKeyDown
onkeyuponKeyUp
onkeypressonKeyPress
onmousedownonMouseDown
onmouseuponMouseUp
onmouseoveronMouseOver
onmouseoutonMouseOut
onmousemoveonMouseMove
onmouseenteronMouseEnter
onmouseleaveonMouseLeave
onloadonLoad
onerroronError
onscrollonScroll
onwheelonWheel
ondragstartonDragStart
ondragendonDragEnd
ondragoveronDragOver
ondroponDrop
ontouchstartonTouchStart
ontouchendonTouchEnd
ontouchmoveonTouchMove
Event handler values are wrapped in an arrow function: onclick="doSomething()"onClick={() => { doSomething() }}.

VOID_ELEMENTS — self-closing elements

The following elements are always self-closed in the JSX output regardless of whether the source HTML included a closing tag: area, base, br, col, embed, hr, img, input, link, meta, param, source, track, wbr

BOOLEAN_ATTRS — boolean attribute handling

Boolean attributes (disabled, checked, selected, multiple, required, readonly, hidden, open, reversed, loop, muted, controls, autoplay, defer, async, allowfullscreen) are emitted as bare JSX props when the HTML value is absent, empty, or equal to the attribute name:
<!-- HTML -->
<input disabled />
<input disabled="" />

<!-- JSX output -->
<input disabled />

Inline style conversion

Inline style= strings are converted to JSX style objects:
<!-- HTML -->
<div style="background-image: url('hero.png'); color: red; z-index: 10">

<!-- JSX output -->
<div style={{backgroundImage: "url('hero.png')", color: "red", zIndex: 10}}>
CSS property names are converted to camelCase. Pure integer values (e.g. z-index: 10) are emitted as number literals; all other values are quoted strings. The parser correctly handles complex CSS values including url("..."), calc(), var(), and values that contain semicolons or colons inside parentheses.

formatJSX

function formatJSX(jsx: string, baseIndent?: number): string
Formats a raw JSX string with proper tree indentation. Called by the pipeline after compileHTMLToJSX to produce readable component files.
ParameterTypeDefaultDescription
jsxstringRaw JSX string to format
baseIndentnumber0Starting indent depth (in 2-space units). Pass 2 to indent the entire block by 4 spaces (for content inside return (...))
Returns a formatted JSX string with two-space indentation per level. Each tag, closing tag, text node, and JSX expression block is placed on its own line at the appropriate depth.

requiresClientDirective

function requiresClientDirective(jsx: string): boolean
Detects whether a component’s JSX content requires the Next.js 'use client' directive. The pipeline calls this automatically when generating Next.js component files and prepends the directive when true. Returns true if the JSX contains any of: Event handler props:
  • onClick, onChange, onSubmit, onInput, onFocus, onBlur
React hooks:
  • useState, useEffect, useRef, useContext, useReducer
Interactive elements:
  • <button> — always interactive in the browser; always needs a client boundary
This check is conservative by design. If you add hooks or event handlers to a component after generation, you must add 'use client' manually. project-context.md includes a reminder about this in its fix checklist.

Example

import { compileHTMLToJSX, formatJSX, requiresClientDirective } from './pipeline/compiler';

const html = `
  <div class="flex flex-col gap-4">
    <h1 class="text-2xl font-bold">Hello World</h1>
    <button onclick="handleClick()">Click me</button>
  </div>
`;

const jsx = compileHTMLToJSX(html);
// <div className="flex flex-col gap-4">
//   <h1 className="text-2xl font-bold">Hello World</h1>
//   <button onClick={() => { handleClick() }}>Click me</button>
// </div>

const formatted = formatJSX(jsx, 2);
// Indented at depth 2 for placement inside return (...)

const needsClient = requiresClientDirective(jsx);
// true — because <button> is present

Build docs developers (and LLMs) love