restache

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 27, 2025 License: MIT Imports: 15 Imported by: 0

README

restache

Mustache-like extension to HTML syntax, designed for use with React and transpiled into JSX.

Getting started

Installation

To use Restache in your project, you'll need to integrate the ESBuild plugin:

go get github.com/tetsuo/restache
Usage
1. Define a template

For example, to list fruits, create fruits.stache:

<ul>
  {#items}
    <li>{name}</li>
  {/items}
</ul>
2. Configure ESBuild with the plugin
import (
  "github.com/evanw/esbuild/pkg/api"
  "github.com/tetsuo/restache"
)

func main() {
  api.Build(api.BuildOptions{
    EntryPoints: []string{"main.mjs"},
    Bundle:      true,
    Plugins:     []api.Plugin{restache.Plugin()},
    Outfile:     "out.js",
  })
}
3. Import .stache files as React components
import Fruits from './fruits.stache'
import { createRoot } from 'react-dom/client'

const root = createRoot(document.getElementById('root'))
root.render(Fruits({ items: [{ name: 'Apple', key: 'apple' }] }))
4. Build your project

Run your build process, and .stache files will be transpiled into JSX automatically.

A more complete usage example is available in the tetsuo/dashboard repository.

Syntax

Variables

Use {variableName} to interpolate variables.

Conditionals
When

{?isVisible}...{/isVisible} renders content when the condition is true.

Unless

{^isHidden}...{/isHidden} renders content when the condition is false.

Loops

{#list}...{/list} iterates over a list.

Components

Define components using custom tags, which are resolved based on naming conventions and mappings.

Component resolution

Restache resolves component tags by:

  1. PascalCasing: Converting tag names to PascalCase.
  2. Prefix Mapping: Using configured prefixes to locate components.
  3. Tag Mappings: Directly mapping tag names to component paths.

These mappings are configured via the ESBuild plugin options.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrErrorNode       = errors.New("cannot render an ErrorNode node")
	ErrUnknownNode     = errors.New("unknown node type")
	ErrVoidChildren    = errors.New("void element has child nodes")
	ErrTooManyChildren = errors.New("node allows only a single child")
	ErrChildOnly       = errors.New("node must appear inside an element node")
	ErrTopLevelOnly    = errors.New("node must appear at the top level")
	ErrMissingBody     = errors.New("node must have children")
)

Functions

func Plugin

func Plugin(opts ...PluginOption) api.Plugin

func Render

func Render(w io.Writer, n *Node) (int, error)

Types

type Attribute

type Attribute struct {
	Key     string
	KeyAtom atom.Atom
	Val     string
	IsExpr  bool
}

type Node

type Node struct {
	Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node

	Type     NodeType
	DataAtom atom.Atom
	Data     string
	Attr     []Attribute
	Path     []PathComponent
}

func Parse

func Parse(r io.Reader) (node *Node, err error)

func (*Node) AppendChild

func (n *Node) AppendChild(c *Node)

AppendChild adds a node c as a child of n.

It will panic if c already has a parent or siblings.

func (*Node) InsertBefore

func (n *Node) InsertBefore(newChild, oldChild *Node)

InsertBefore inserts newChild as a child of n, immediately before oldChild in the sequence of n's children. oldChild may be nil, in which case newChild is appended to the end of n's children.

It will panic if newChild already has a parent or siblings.

func (*Node) RemoveChild

func (n *Node) RemoveChild(c *Node)

RemoveChild removes a node c that is a child of n. Afterwards, c will have no parent and no siblings.

It will panic if c's parent is not n.

func (*Node) Render added in v0.2.0

func (n *Node) Render(w writer) (int, error)

func (*Node) TagName

func (n *Node) TagName() string

type NodeType

type NodeType uint32
const (
	ErrorNode NodeType = iota
	TextNode
	ComponentNode
	ElementNode
	CommentNode
	VariableNode
	RangeNode
	WhenNode
	UnlessNode
)

type PathComponent

type PathComponent struct {
	Key     string
	IsRange bool
}

type PluginOption added in v0.2.0

type PluginOption func(*pluginConfig)

func WithExtensionName added in v0.2.0

func WithExtensionName(extName string) PluginOption

func WithTagMappings added in v0.2.0

func WithTagMappings(tagMappings map[string]string) PluginOption

func WithTagPrefixes added in v0.2.0

func WithTagPrefixes(tagPrefixes map[string]string) PluginOption

type TokenType

type TokenType uint32

TokenType represents the type of token.

const (
	ErrorToken TokenType = iota
	StartTagToken
	EndTagToken
	SelfClosingTagToken
	TextToken
	CommentToken
	VariableToken
	WhenToken
	UnlessToken
	RangeToken
	EndControlToken
)

type Tokenizer

type Tokenizer struct {
	// contains filtered or unexported fields
}

Tokenizer holds state for parsing.

func NewTokenizer

func NewTokenizer(r io.Reader) *Tokenizer

func (*Tokenizer) Comment

func (t *Tokenizer) Comment() []byte

Comment extracts the content of a comment.

func (*Tokenizer) ControlName

func (t *Tokenizer) ControlName() []byte

ControlName extracts the name of a section, inverted section, or end section.

func (*Tokenizer) Err

func (t *Tokenizer) Err() error

Err returns the last error encountered by the tokenizer.

func (*Tokenizer) Next

func (t *Tokenizer) Next() TokenType

Next advances the tokenizer to the next token and returns its type.

func (*Tokenizer) Raw

func (t *Tokenizer) Raw() []byte

Raw returns the raw byte slice of the current token.

func (*Tokenizer) TagAttr

func (t *Tokenizer) TagAttr() (key []byte, val []byte, isExpr bool, moreAttr bool)

TagAttr retrieves the next attribute key and value from an HTML start tag.

func (*Tokenizer) TagName

func (t *Tokenizer) TagName() ([]byte, bool)

TagName returns the name of the current HTML tag, if applicable.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL