Skip to content

hsml-lab/hsml

Repository files navigation

Crate Downloads NPM Downloads CI codecov License: MIT Donate: PayPal

HSML - Hyper Short Markup Language

A pug-inspired HTML preprocessor, written in Rust. Less typing, more shipping.

Still young and growing! Some features are cooking. Check out the roadmap below.

What is it?

HSML compiles a short, indentation-based syntax into HTML — think Pug, but leaner:

  • TailwindCSS-friendly — arbitrary values like .bg-[#1da1f2] and lg:[&:nth-child(3)]:hover:underline just work
  • No template engine — HSML is to HTML what TypeScript is to JavaScript: a compile-time transformation, no runtime
  • Rust-powered — fast native CLI + WASM package for browser and bundler use
  • Helpful diagnostics — descriptive errors and warnings with source context, like a good compiler should

Quick taste

doctype html
html
  head
    title My Page
  body
    h1.text-xl.font-bold Hello World
    .card
      img.rounded-full(src="/avatar.jpg" alt="Me")
      p.text-gray-500 Nice to meet you!

Compiles to:

<!DOCTYPE html>
<html>
  <head>
    <title>My Page</title>
  </head>
  <body>
    <h1 class="text-xl font-bold">Hello World</h1>
    <div class="card">
      <img class="rounded-full" src="/avatar.jpg" alt="Me" />
      <p class="text-gray-500">Nice to meet you!</p>
    </div>
  </body>
</html>

Installation

CLI (via Cargo)

cargo install hsml

WASM (via npm)

npm install -D hsml
# or
pnpm add -D hsml
# or
bun add -D hsml

Usage

CLI

# Compile a single file
hsml compile index.hsml

# Compile to a specific output file
hsml compile index.hsml -o output.html

# Compile all .hsml files in a directory
hsml compile src/

# Check files for errors and warnings without compiling
hsml check src/

# Get diagnostics as JSON (for CI integration)
hsml compile index.hsml --report-format json
hsml check src/ --report-format json

# GitHub Actions annotations
hsml check src/ --report-format github

# GitLab Code Quality report
hsml check src/ --report-format gitlab

# Debug output with timing
hsml compile src/ --debug

# Disable colored output
hsml compile src/ --no-color

Ignore patterns

When compiling or checking a directory, HSML automatically skips:

  • Hidden files and directories (e.g. .git/, .cache/)
  • Built-in ignores: node_modules/, target/, dist/, build/, .hg/, .svn/
  • .gitignore patterns (works even outside git repositories)
  • .hsmlignore patterns (same format as .gitignore)

You can also pass ignore patterns via CLI:

hsml compile src/ --ignore-pattern "vendor/"
hsml check src/ --ignore-pattern "tmp/" --ignore-pattern "generated/"

To re-include a built-in ignored directory, add a negation to .hsmlignore:

# .hsmlignore
!build/

WASM / JavaScript

import { compileContent, compileContentWithDiagnostics } from "hsml";

// Simple compilation
const html = compileContent("h1.title Hello World\n");
// => '<h1 class="title">Hello World</h1>'

// With diagnostics (errors + warnings)
const result = compileContentWithDiagnostics("h1.foo.foo Hello\n");
// => { success: true, html: '...', diagnostics: [{ severity: 'warning', code: 'W002', ... }] }

HSML Syntax

Tags

h1 Hello World
div
  p Some text

Tags default to div when only a class or id is specified:

.container
  .card
    .card-body Hello

Classes

h1.text-red.font-bold Hello

TailwindCSS arbitrary values are fully supported:

.bg-[#1da1f2].lg:[&:nth-child(3)]:hover:underline

IDs

div#app
  h1#title Hello

Attributes

img(src="/photo.jpg" alt="A photo" width="300")
a(href="https://github.com" target="_blank") GitHub
button(disabled) Click me

Multiline attributes work too:

img(
  src="/photo.jpg"
  alt="A photo"
  width="300"
  height="200"
)

Text blocks

Use a trailing . to start a text block:

p.
  This is a multi-line
  text block that preserves
  line breaks.

Comments

// Dev comment (excluded from HTML output)
//! Native comment (rendered as <!-- ... -->)

Doctype

doctype html

Vue / Angular support

HSML supports framework-specific attribute syntax out of the box:

// Vue
button(@click="handleClick" :class="dynamicClass" v-if="show") Click
template(#default)
  p Slot content

// Angular
button([disabled]="isDisabled" (click)="onClick()") Click

Diagnostics

HSML provides helpful error messages with source context:

error[E001]: Tag name must start with an ASCII letter
 --> example.hsml:1:1
  |
1 | 42div Hello
  | ^

And warnings for common mistakes:

warning[W002]: Duplicate class 'foo'
 --> example.hsml:1:12
  |
1 | h1.foo.foo Hello
  |        ^

Error & warning codes

Code Description
E001 Tag name must start with an ASCII letter
E002 Unclosed bracket
E003 Unclosed parenthesis
E004 Unclosed quote in attribute value
E005 Expected quoted attribute value
E006 Invalid attribute key
W001 Duplicate id (only one per element)
W002 Duplicate class
W003 Mixed tabs and spaces in indentation
W004 Duplicate attribute
W005 Void element cannot have content
W006 Empty attribute parentheses

Roadmap

  • Parser with TailwindCSS support
  • HTML compiler
  • CLI with compile command
  • WASM package for npm
  • Diagnostic system with errors and warnings
  • JSON diagnostic output (--report-format json)
  • hsml check — standalone linting command
  • Ignore support (.gitignore, .hsmlignore, --ignore-pattern)
  • hsml fmt — code formatter
  • hsml parse — AST output as JSON
  • LSP server with diagnostics and hover
  • GitHub/GitLab CI diagnostic formatters

Contributing

See CONTRIBUTING.md for development setup and commands.

License

MIT — go wild.

About

A pug-inspired HTML preprocessor

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages