Herb Toolchain

repository·main·Indexed 22 days ago

https://github.com/marcoroth/herb

A comprehensive toolchain for HTML+ERB (.html.erb) templates providing high-fidelity parsing, linting, formatting, and rendering. The ecosystem includes @herb-tools/formatter for ERB-aware pretty-printing, @herb-tools/language-server for LSP integration, @herb-tools/highlighter for syntax highlighting, and @herb-tools/browser for WebAssembly-based parsing in browser environments. It also features a Dev Server client for live updates and Java/JNI bindings for native integration.

Tokens
92.2K
Snippets
265
Records
536
Agent score
78%

What's inside Herb

  1. What is Herb?

    main

    Herb is a modern HTML+ERB (.html.erb) toolchain and ecosystem designed to provide precise, accurate developer tools for HTML-aware ERB templates.

    At its core is the Herb Parser, a fast, portable, HTML-aware ERB parser written in C that generates a detailed syntax tree. This parser powers the entire ecosystem, including:

    • Developer Tools: CLI, language server, formatter, linter, and browser dev tools.
    • Language Bindings: Support for Ruby, Node.js, Java, Rust, and the Browser (via WebAssembly).
    • Utility Libraries: Language service, highlighter, minifier, and printer.
    • Herb Engine: An HTML-aware ERB rendering engine (Herb::Engine) that is API-compatible with Erubi but adds structural awareness for features like HTML validation and security checks.
  2. Overview of the Herb Parser (libherb)

    main
    The Herb Parser (libherb) is a C library designed for high-performance, portable, and HTML-aware ERB parsing. It serves as the foundational component for the entire Herb ecosystem, responsible for generating detailed and accurate syntax trees from templates that combine HTML and ERB. It is suitable for developers needing a low-level, fast parsing engine for HTML+ERB content.
  3. Overview of the Herb ecosystem projects

    main

    The Herb ecosystem provides tooling for HTML+ERB and is organized into three functional categories:

    1. Developer Tools: User-facing tools for direct integration into development workflows (e.g., Language Server, Formatter, Linter, Dev Server, CLI).
    2. Language Bindings: Libraries that provide access to the Herb Parser across different environments (C, Ruby, JavaScript/Node.js, and WebAssembly).
    3. Utility Libraries: Specialized libraries supporting the ecosystem, including clients, language services, highlighters, printers, and core logic.
  4. Use the Herb Java API for Lexing, Parsing, and Extraction

    main

    The org.herb package provides static methods via the Herb class to process HTML documents with embedded Ruby (HTML+ERB) through JNI.

    Key capabilities include:

    • Lexing: Tokenizing source code into a stream of tokens.
    • Parsing: Generating an Abstract Syntax Tree (AST) from the source.
    • Extraction: Isolating either the Ruby code or the HTML content from a mixed source.
  5. How Action View Tag Helpers are represented in the AST

    main

    When action_view_helpers is enabled, Action View helpers are transformed into synthetic HTMLElementNode AST representations.

    Key features of this transformation:

    • The open tag is represented as an ERBOpenTagNode.
    • The closing <% end %> is mapped to the close_tag of the HTML element.
    • The element_source field identifies the specific helper that produced the node (e.g., ActionView::Helpers::TagHelper#tag).
    • Attributes like data: { controller: "hello" } are flattened into standard HTMLAttributeNode entries (e.g., name: "data-controller", value: "hello").
  6. Integrate Herb Linter with Language Servers

    main

    The Herb Linter is automatically integrated into the Herb Language Server. This provides real-time validation and diagnostics in supported editors such as VS Code, Zed, and Neovim.

    Tip: Hot Reloading Custom rules are automatically reloaded when changed in editors using the Herb Language Server, meaning you do not need to restart your editor to see changes to your custom rule logic.

  7. Rule-Level File Patterns Precedence

    main

    When configuring specific rules in .herb.yml, you can control which files they apply to using include, only, and exclude. These follow a strict precedence order:

    1. only: If present, the rule applies ONLY to these files. This ignores any include settings.
    2. include: If only is absent, the rule applies to these files (this is additive to the global include settings).
    3. exclude: Always applied. If a file matches an exclude pattern, the rule will not run on it (unless using the --force flag).
  8. Understand configuration merging and priority

    main

    Herb merges configuration patterns in a specific hierarchy. Patterns at every level are additive to the defaults. The order of precedence for determining the final list of patterns is:

    1. Defaults: Built-in patterns (e.g., node_modules/**/* is excluded by default).
    2. Top-level files.include/files.exclude: Patterns defined in .herb.yml under the files key.
    3. Tool-level patterns: Patterns defined under specific tool keys like linter.include or formatter.exclude.

    Example logic: If you have files.include: ['**/*.xml.erb'] and linter.include: ['**/*.custom.erb'], the linter will use the union of: Defaults + **/*.xml.erb + **/*.custom.erb.