templ

package module
v0.0.114 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2021 License: MIT Imports: 15 Imported by: 2,811

README

templ

  • A strongly typed HTML templating language that compiles to Go code, and has great developer tooling.

vscode-autocomplete

Getting started

  • Install the templ command-line tool: go install github.com/a-h/templ/cmd/templ@latest
  • Create a *.templ file containing a template.
  • Run templ generate to create Go code from the template.

Current state

This is beta software, and the template language may still have breaking changes. There's no guarantees of stability or correctness at the moment, but it has at least one production user.

If you're keen to see Go be practical for Web projects, see "Help needed" for where the project needs your help.

Features

The language generates Go code, some sections of the template (e.g. package, import, if, for and switch statements) are output directly as Go expressions in the generated output, while HTML elements are converted to Go code that renders their output.

  • templ generate generates Go code from *.templ files.
  • templ fmt formats template files in the current directory tree.
  • templ lsp provides a Language Server to support IDE integrations. The compile command generates a sourcemap which maps from the *.templ files to the compiled Go file. This enables the templ LSP to use the Go language gopls language server as is, providing a thin shim to do the source remapping. This is used to provide autocomplete for template variables and functions.

Security

templ will automatically escape content according to the following rules.

{% templ Example() %}
  <script type="text/javascript">
    {%= "will be HTML encoded using templ.Escape, which isn't JavaScript-aware, don't use templ to build scripts" %}
  </script>
  <div onClick={%= "will be HTML encoded using templ.Escape, but this isn't JavaScript aware, don't use user-controlled data here" %}>
    {%= "will be HTML encoded using templ.Escape" %}</div>  
  </div>
  <style type="text/css">
    {%= "will be escaped using templ.Escape, which isn't CSS-aware, don't use user-controlled data here" %}
  </style>
  <div style={%= "will be HTML encoded using templ.Escape, which isn't CSS-aware, don't use user controlled data here" %}</div>
  <div class={%= templ.CSSClasses(templ.Class("will not be escaped, because it's expected to be a constant value")) %}</div>
  <div>{%= "will be escaped using templ.Escape" %}</div>
  <a href="http://constants.example.com/are/not/sanitized">Text</a>
  <a href={%= templ.URL("will be sanitized by templ.URL to remove potential attacks") %}</div>
  <a href={%= templ.SafeURL("will not be sanitized by templ.URL") %}</div>
{% endtempl %}

CSS property names, and constant CSS property values are not sanitized or escaped.

{% css className() %}
	background-color: #ffffff;
{% endcss %}

CSS property values based on expressions are passed through templ.SanitizeCSS to replace potentially unsafe values with placeholders.

{% css className() %}
	color: {%= red %};
{% endcss %}

Design

Overview
  • *.templ files are used to generate Go code to efficiently render the template at runtime.
  • Go code is generated from template files using the templ generate command, while templates can be formatted with the templ fmt command. The templ lsp command provides an LSP (Language Server Protocol) server to enable autocomplete.
  • Each {% templ ComponentName(params Params) %} section compiles into a function that creates a templ.Component.
  • templ.Component is an interface with a single function - Render(ctx context.Context, io.Writer) (err error). You can make a component entirely in Go code and interact with it via templ.
  • templ aims for correctness, simplicity, developer experience and raw performance, in that order. The goal is to make writing Go web applications more practical, achievable and desirable.
  • Provides minified HTML output only.
  • Components can be composed into layouts.
Package

Since templ files are as close to Go as possible, they start with a package expression.

{% package templ %}
Importing packages

After the package expression, they might import other Go packages, just like Go files. There's no multi-line import statement, just a single import per line.

{% import "strings" %}
Components

Once the package and import statements are done, we can define components using the {% templ Name(params Params) %} expression. The templ expressions are converted into Go functions when the templ generate command is executed.

{% templ AddressView(addr Address) %}
	<div>{%= addr.Address1 %}</div>
	<div>{%= addr.Address2 %}</div>
	<div>{%= addr.Address3 %}</div>
	<div>{%= addr.Address4 %}</div>
{% endtempl %}

Each templ.Component can contain HTML elements, strings, for loops, switch statements and references to other templates.

Referencing other components

Components can be referenced in the body of the template, and can pass data between then, for example, using the AddressTemplate from the PersonTemplate.

{% templ PersonTemplate(p Person) %}
	<div>
	    {% for _, v := range p.Addresses %}
		    {%! AddressTemplate(v) %}
	    {% endfor %}
	</div>
{% endtempl %}

It's also possible to create "higher order components" that compose other instances of templ.Component without passing data, or even knowing what the concrete type of the component will be ahead of time. So long as is implements templ.Component, it can be used.

For example, this template accepts 3 templates (header, footer, body) and renders all 3 of them in the expected order.

{% templ Layout(header, footer, body templ.Component) %}
	{%! header %}
	{%! body %}
	{%! footer %}
{% endtempl %}
Code-only components

It's possible to create a templ.Component entirely in Go code. Within templ, strings are automatically escaped to reduce the risk of cross-site-scripting attacks, but it's possible to create your own "Raw" component that bypasses this behaviour:

func Raw(s string) templ.Component {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
		_, err = io.WriteString(w, s)
		return
	})
}

Then call it in a template. So long as the Raw function is in scope, you can use it.

{%! Raw("<script>alert('xss vector');</script>") %}
Elements

HTML elements look like HTML and you can write static attributes into them, just like with normal HTML. Don't worry about the spacing, the HTML will be minified when it's rendered.

<div id="address1">{%= addr.Address1 %}</div>

You can also have dynamic attributes that use template parameter, other Go variables that happen to be in scope, or call Go functions that return a string. Don't worry about HTML encoding element text and attribute values, that will be taken care of automatically.

<a title={%= p.TitleText %}>{%= strings.ToUpper(p.Name()) %}</a>

However, the a element's href attribute is treated differently. Templ expects you to provide a templ.SafeURL. A templ.SafeURL is a URL that is definitely safe to use (i.e. has come from a configuration system controlled by the developer), or has been through a sanitization process to filter out potential XSS attacks.

Templ provides a templ.URL function that sanitizes input URLs and checks that the protocol is http/https/mailto rather than javascript or another unexpected protocol.

<a href={%= templ.URL(p.URL) %}>{%= strings.ToUpper(p.Name()) %}</a>
Text

Text is rendered from Go expressions, which includes constant values:

{%= "this is a string" %}

Using the backtick format (single-line only):

{%= `this is also a string` %}

Calling a function that returns a string:

{%= time.Now().String() %}

Or using a string parameter, or variable that's in scope.

{%= v.s %}

What you can't do, is write text directly between elements (e.g. <div>Some text</div>, because the parser would have to become more complex to support HTML entities and the various mistakes people make when they're doing that (bare ampersands etc.). Go strings support UTF-8 which is much easier, and the escaping rules are well known by Go programmers.

CSS

Templ components can have CSS associated with them. CSS classes are created with the css template expression. CSS properties can be set to string variables or functions (e.g. {%= red %}). However, functions should be idempotent - i.e. return the same value every time.

All variable CSS values are passed through a value sanitizer to provide some protection against malicious data being added to CSS.

{% css className() %}
	background-color: #ffffff;
	color: {%= red %};
{% endcss %}

CSS class components can be used within templates.

{% templ Button(text string) %}
	<button class={%= templ.Classes(className(), templ.Class("other")) %} type="button">{%= text %}</button>
{% endtempl %}

The first time that the component is rendered in a HTTP request, it will render the CSS class to the output. The next time the same component is rendered, templ will skip rendering the CSS to the output because it is no longer required.

For example, if this template is rendered in a request:

{% templ TwoButtons() %}
	{%! Button("A") %}
	{%! Button("B") %}
{% endtempl %}

The output would contain one class. Note that the name contains a unique value is addition to the class name to reduce the likelihood of clashes. Don't rely on this name being consistent.

<style type="text/css">.className_f179{background-color:#ffffff;color:#ff0000;}</style>
<button class="className_f179 other" type="button">A</button>
<button class="className_f179 other" type="button">B</button>`
CSS Middleware

If you want to provide a global stylesheet that includes this CSS to remove <style> tags from the output, you can use templ's CSS middleware, and register templ classes.

The middleware adds a HTTP route to the web server (/styles/templ.css by default) that renders the text/css classes that would otherwise be added to <style> tags when components are rendered. It's then your responsibility to add a <link rel="stylesheet" href="/styles/templ.css"> to your HTML.

For example, to stop the className CSS class from being added to the output, the HTTP middleware can be used.

c1 := className()
handler := NewCSSMiddleware(httpRoutes, c1)
http.ListenAndServe(":8000:, handler)
If/Else

Templates can contain if/else statements that follow the same pattern as Go.

{% if p.Type == "test" %}
	<span>{%= "Test user" %}</span>
{% else %}
	<span>{%= "Not test user" %}</span>
{% endif %}
For

Templates have the same loop behaviour as Go.

{% for _, v := range p.Addresses %}
	<li>{%= v.City %}</li>
{% endfor %}
Switch/Case

Switch statements work in the same way as they do in Go.

{% switch p.Type %}
	{% case "test" %}
		<span>{%= "Test user" %}</span>
	{% endcase %}
	{% case "admin" %}
		<span>{%= "Admin user" %}</span>
	{% endcase %}
	{% default %}
		<span>{%= "Unknown user" %}</span>
	{% enddefault %}
{% endswitch %}

Full example

{% package templ %}

{% import "strings" %}

{% templ Layout(header, footer, body templ.Component) %}
	{%! header %}
	{%! body %}
	{%! footer %}
{% endtempl %}

{% templ AddressTemplate(addr Address) %}
	<div>{%= addr.Address1 %}</div>
	<div>{%= addr.Address2 %}</div>
	<div>{%= addr.Address3 %}</div>
	<div>{%= addr.Address4 %}</div>
{% endtempl %}

{% templ PersonTemplate(p Person) %}
	<div>
		<div>{%= p.Name() %}</div>
		<a href={%= p.URL %}>{%= strings.ToUpper(p.Name()) %}</a>
		<div>
			{% if p.Type == "test" %}
				<span>{%= "Test user" %}</span>
			{% else %}
				<span>{%= "Not test user" %}</span>
			{% endif %}
			{% for _, v := range p.Addresses %}
				{%! AddressTemplate(v) %}
			{% endfor %}
			{% switch p.Type %}
				{% case "test" %}
					<span>{%= "Test user" %}</span>
				{% endcase %}
				{% case "admin" %}
					<span>{%= "Admin user" %}</span>
				{% endcase %}
				{% default %}
					<span>{%= "Unknown user" %}</span>
				{% enddefault %}
			{% endswitch %}
		</div>
	</div>
{% endtempl %}

Will compile to Go code similar to the following (error handling removed for brevity):

// Code generated by templ DO NOT EDIT.

package templ

import "github.com/a-h/templ"
import "context"
import "io"
import "strings"

func Layout(header, footer, body templ.Component) (t templ.Component) {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
		err = header.Render(ctx, w)
		err = body.Render(ctx, w)
		err = footer.Render(ctx, w)
		return err
	})
}

func AddressTemplate(addr Address) (t templ.Component) {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
		_, err = io.WriteString(w, "<div>")
		_, err = io.WriteString(w, templ.EscapeString(addr.Address1))
		_, err = io.WriteString(w, "</div>")
		_, err = io.WriteString(w, "<div>")
		_, err = io.WriteString(w, templ.EscapeString(addr.Address2))
		_, err = io.WriteString(w, "</div>")
		// Cut for brevity.
		return err
	})
}

func PersonTemplate(p Person) (t templ.Component) {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
		_, err = io.WriteString(w, "<div>")
		_, err = io.WriteString(w, "<div>")
		_, err = io.WriteString(w, templ.EscapeString(p.Name()))
		_, err = io.WriteString(w, "</div>")
		_, err = io.WriteString(w, "<a")
		_, err = io.WriteString(w, " href=")
		_, err = io.WriteString(w, "\"")
		_, err = io.WriteString(w, templ.EscapeString(p.URL))
		_, err = io.WriteString(w, "\"")
		_, err = io.WriteString(w, ">")
		_, err = io.WriteString(w, templ.EscapeString(strings.ToUpper(p.Name())))
		_, err = io.WriteString(w, "</a>")
		_, err = io.WriteString(w, "<div>")
		if p.Type == "test" {
			_, err = io.WriteString(w, "<span>")
			_, err = io.WriteString(w, templ.EscapeString("Test user"))
			_, err = io.WriteString(w, "</span>")
		} else {
			_, err = io.WriteString(w, "<span>")
			_, err = io.WriteString(w, templ.EscapeString("Not test user"))
			_, err = io.WriteString(w, "</span>")
		}
		for _, v := range p.Addresses {
			err = AddressTemplate(v).Render(ctx, w)
		}
		switch p.Type {
		case "test":
			_, err = io.WriteString(w, "<span>")
			_, err = io.WriteString(w, templ.EscapeString("Test user"))
			_, err = io.WriteString(w, "</span>")
		case "admin":
			_, err = io.WriteString(w, "<span>")
			_, err = io.WriteString(w, templ.EscapeString("Admin user"))
			_, err = io.WriteString(w, "</span>")
		default:
		        _, err = io.WriteString(w, "<span>")
			_, err = io.WriteString(w, templ.EscapeString("Unknown user"))
			_, err = io.WriteString(w, "</span>")
		}
		_, err = io.WriteString(w, "</div>")
		_, err = io.WriteString(w, "</div>")
		return err
	})
}

IDE Support

vim / neovim

A vim / neovim plugin is available from https://github.com/Joe-Davidson1802/templ.vim which adds syntax highlighting.

Neovim 5 supports Language Servers directly. For the moment, I'm using https://github.com/neoclide/coc.nvim to test the language server after using Joe-Davidson1802's plugin to set the language type:

{
  "languageserver": {
    "templ": {
      "command": "templ",
      "args": ["lsp"],
      "filetypes": ["templ"]
    }
}

To add extensive debug information, you can include additional args to the LSP, like this:

{
  "languageserver": {
    "templ": {
      "command": "templ",
      "args": ["lsp",
        "--log", "/Users/adrian/github.com/a-h/templ/cmd/templ/lspcmd/templ-log.txt", 
	"--goplsLog", "/Users/adrian/github.com/a-h/templ/cmd/templ/lspcmd/gopls-log.txt",
	"--goplsRPCTrace", "true"
      ],
      "filetypes": ["templ"]
    }
}

vscode

There's a VS Code extension, just make sure you've already installed templ and that it's on your path.

Development

Local builds

To build a local version you can use the go build tool:

cd cmd/templ
go build

Testing

Unit tests use the go test tool:

go test ./...

Release testing

This project uses https://github.com/goreleaser/goreleaser to build the command line binary and deploy it to Github. You will need to install this to test releases.

make build-snapshot

The binaries are created by me and signed by my GPG key. You can verify with my key https://adrianhesketh.com/a-h.gpg

Inspiration

Doesn't this look like a lot like https://github.com/valyala/quicktemplate ?

Yes, yes it does. I looked at the landscape of Go templating languages before I started writing code and my initial plan was to improve the IDE support of quicktemplate, see https://github.com/valyala/quicktemplate/issues/80

The package author didn't respond (hey, we're all busy), and looking through the code, I realised that it would be hard to modify what's there to have the concept of source mapping, mostly because there's no internal object model of the language, it reads and emits code in one go.

It's also a really feature rich project, with all sorts of formatters, and support for various languages (JSON etc.), so I borrowed some syntax ideas, but left the code. If valyala is up for it, I'd be happy to help integrate the ideas from here. I just want Go to have a templating language with great IDE support.

Hot reload

For hot reload, you can use https://github.com/cosmtrek/air

For documentation on how to use it with templ see https://adrianhesketh.com/2021/05/28/templ-hot-reload-with-air/

Help needed

The project is looking for help with:

  • Adding features to the Language Server implementation, it just does autocomplete and error reporting the moment. It needs to be able to do definition and add imports automatically.
  • Examples and testing of the tools.
  • Writing a blog post that demonstrates using the tool to build a form-based Web application.
  • Testing (including fuzzing), benchmarking and optimisation.
  • An example of a web-based UI component library would be very useful, a more advanced version of the integration test suite, thatwould be a Go web server that runs the compiled templ file along with example JSON payloads that match the expected data structure types and renders the content - a UI playground. If it could do hot-reload, amazing.
  • Low priority, but I'm thinking of developing a CSS-in-Go implementation to work in parallel. This might take the form of a pre-processor which would collect all "style" attributes of elements and automatically calculate a minimum set of CSS classes that could be created and applied to the elements - but a first pass could just be a way to define CSS classes in Go to allow the use of CSS variables.

Please get in touch if you're interested in building a feature as I don't want people to spend time on something that's already being worked on, or ends up being a waste of their time because it can't be integrated.

Writing and examples

Documentation

Index

Constants

View Source
const FailedSanitizationURL = SafeURL("about:invalid#TemplFailedSanitizationURL")

FailedSanitizationURL is returned if a URL fails sanitization checks.

Variables

This section is empty.

Functions

func CSSID added in v0.0.113

func CSSID(name string, css string) string

CSSID calculates an ID.

func EscapeString

func EscapeString(s string) string

EscapeString escapes HTML text within templates.

func RenderCSS added in v0.0.113

func RenderCSS(ctx context.Context, w io.Writer, classes []CSSClass) (err error)

Render CSS renders a <style> element with CSS content, if the styles have not already been rendered.

Types

type Attribute

type Attribute interface {
	IsAttribute() bool
	String() string
}

type CSSClass added in v0.0.113

type CSSClass interface {
	ClassName() string
}

CSSClass provides a class name.

func Class added in v0.0.113

func Class(name string) CSSClass

Class returns a static CSS class name.

type CSSClasses added in v0.0.113

type CSSClasses []CSSClass

CSSClasses is a slice of CSS classes.

func Classes added in v0.0.113

func Classes(classes ...CSSClass) CSSClasses

Classes for CSS.

func (CSSClasses) String added in v0.0.113

func (classes CSSClasses) String() string

String returns the names of all CSS classes.

type CSSHandler added in v0.0.113

type CSSHandler struct {
	Classes []ComponentCSSClass
}

CSSHandler is a HTTP handler that serves CSS.

func NewCSSHandler added in v0.0.113

func NewCSSHandler(classes ...ComponentCSSClass) CSSHandler

NewCSSHandler creates a handler that serves a stylesheet containing the CSS of the classes passed in. This is used by the CSSMiddleware to provide global stylesheets for templ components.

func (CSSHandler) ServeHTTP added in v0.0.113

func (cssh CSSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)

type CSSMiddleware added in v0.0.113

type CSSMiddleware struct {
	Path       string
	CSSHandler CSSHandler
	Next       http.Handler
}

CSSMiddleware renders a global stylesheet.

func NewCSSMiddleware added in v0.0.113

func NewCSSMiddleware(next http.Handler, classes ...ComponentCSSClass) CSSMiddleware

NewCSSMiddleware creates HTTP middleware that renders a global stylesheet of ComponentCSSClass CSS if the request path matches, or updates the HTTP context to ensure that any handlers that use templ.Components skip rendering <style> elements for classes that are included in the global stylesheet. By default, the stylesheet path is /styles/templ.css

func (CSSMiddleware) ServeHTTP added in v0.0.113

func (cssm CSSMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request)

type CSSProperty added in v0.0.113

type CSSProperty interface {
	IsCSSProperty() bool
	Write(w io.Writer, indent int) error
}

CSSProperty is a CSS property and value pair.

type CSSTemplate added in v0.0.113

type CSSTemplate struct {
	Name       Expression
	Properties []CSSProperty
}

CSS definition. {% css Name() %}

color: #ffffff;
background-color: {%= constants.BackgroundColor %};
background-image: url('./somewhere.png');

{% endcss %}

func (CSSTemplate) IsTemplateFileNode added in v0.0.113

func (css CSSTemplate) IsTemplateFileNode() bool

func (CSSTemplate) Write added in v0.0.113

func (css CSSTemplate) Write(w io.Writer, indent int) error

type CallTemplateExpression

type CallTemplateExpression struct {
	// Expression returns a template to execute.
	Expression Expression
}

CallTemplateExpression can be used to create and render a template using data. {%! Other(p.First, p.Last) %} or it can be used to render a template parameter. {%! v %}

func (CallTemplateExpression) IsNode

func (cte CallTemplateExpression) IsNode() bool

func (CallTemplateExpression) Write

func (cte CallTemplateExpression) Write(w io.Writer, indent int) error

type CaseExpression

type CaseExpression struct {
	Expression Expression
	Children   []Node
}

{% case "Something" %} ... {% endcase %}

type Component

type Component interface {
	// Render the template.
	Render(ctx context.Context, w io.Writer) error
}

Component is the interface that all templates implement.

type ComponentCSSClass added in v0.0.113

type ComponentCSSClass struct {
	// ID of the class, will be autogenerated.
	ID string
	// Definition of the CSS.
	Class SafeCSS
}

ComponentCSSClass is a templ.CSS

func (ComponentCSSClass) ClassName added in v0.0.113

func (css ComponentCSSClass) ClassName() string

ClassName of the CSS class.

type ComponentFunc

type ComponentFunc func(ctx context.Context, w io.Writer) error

ComponentFunc converts a function that matches the Component interface's Render method into a Component.

func (ComponentFunc) Render

func (cf ComponentFunc) Render(ctx context.Context, w io.Writer) error

Render the template.

type ConstantAttribute

type ConstantAttribute struct {
	Name  string
	Value string
}

href=""

func (ConstantAttribute) IsAttribute

func (ca ConstantAttribute) IsAttribute() bool

func (ConstantAttribute) String

func (ca ConstantAttribute) String() string

type ConstantCSSClass added in v0.0.113

type ConstantCSSClass string

ConstantCSSClass is a string constant of a CSS class name.

func (ConstantCSSClass) ClassName added in v0.0.113

func (css ConstantCSSClass) ClassName() string

ClassName of the CSS class.

type ConstantCSSProperty added in v0.0.113

type ConstantCSSProperty struct {
	Name  string
	Value string
}

color: #ffffff;

func (ConstantCSSProperty) IsCSSProperty added in v0.0.113

func (c ConstantCSSProperty) IsCSSProperty() bool

func (ConstantCSSProperty) Write added in v0.0.113

func (c ConstantCSSProperty) Write(w io.Writer, indent int) error

type Element

type Element struct {
	Name       string
	Attributes []Attribute
	Children   []Node
}

<a .../> or <div ...>...</div>

func (Element) IsNode

func (e Element) IsNode() bool

func (Element) Write

func (e Element) Write(w io.Writer, indent int) error

type Expression

type Expression struct {
	Value string
	Range Range
}

Expression containing Go code.

func NewExpression

func NewExpression(value string, from, to Position) Expression

NewExpression creates a Go expression.

type ExpressionAttribute

type ExpressionAttribute struct {
	Name       string
	Expression Expression
}

href={%= ... }

func (ExpressionAttribute) IsAttribute

func (ea ExpressionAttribute) IsAttribute() bool

func (ExpressionAttribute) String

func (ea ExpressionAttribute) String() string

type ExpressionCSSProperty added in v0.0.113

type ExpressionCSSProperty struct {
	Name  string
	Value StringExpression
}

background-color: {%= constants.BackgroundColor %};

func (ExpressionCSSProperty) IsCSSProperty added in v0.0.113

func (c ExpressionCSSProperty) IsCSSProperty() bool

func (ExpressionCSSProperty) Write added in v0.0.113

func (c ExpressionCSSProperty) Write(w io.Writer, indent int) error

type ForExpression

type ForExpression struct {
	Expression Expression
	Children   []Node
}

{% for i, v := range p.Addresses %}

{% call Address(v) %}

{% endfor %}

func (ForExpression) IsNode

func (fe ForExpression) IsNode() bool

func (ForExpression) Write

func (fe ForExpression) Write(w io.Writer, indent int) error

type HTMLTemplate added in v0.0.113

type HTMLTemplate struct {
	Name       Expression
	Parameters Expression
	Children   []Node
}

HTMLTemplate definition. {% templ Name(p Parameter) %}

{% if ... %}
<Element></Element>

{% endtempl %}

func (HTMLTemplate) IsTemplateFileNode added in v0.0.113

func (t HTMLTemplate) IsTemplateFileNode() bool

func (HTMLTemplate) Write added in v0.0.113

func (t HTMLTemplate) Write(w io.Writer, indent int) error

type IfExpression

type IfExpression struct {
	Expression Expression
	Then       []Node
	Else       []Node
}

{% if p.Type == "test" && p.thing %} {% endif %}

func (IfExpression) IsNode

func (n IfExpression) IsNode() bool

func (IfExpression) Write

func (n IfExpression) Write(w io.Writer, indent int) error

type Import

type Import struct {
	Expression Expression
}

{% import "strings" %} {% import strs "strings" %}

func (Import) Write

func (imp Import) Write(w io.Writer, indent int) error

type Node

type Node interface {
	IsNode() bool
	// Write out the string.
	Write(w io.Writer, indent int) error
}

A Node appears within a template, e.g. an StringExpression, Element, IfExpression etc.

type Package

type Package struct {
	Expression Expression
}

{% package templ %}

func (Package) Write

func (p Package) Write(w io.Writer, indent int) error

type ParseError added in v0.0.89

type ParseError struct {
	Message string
	From    Position
	To      Position
}

ParseError details where the error occurred in the file.

func (ParseError) Error added in v0.0.89

func (pe ParseError) Error() string

type Position

type Position struct {
	Index int64
	Line  int
	Col   int
}

Source mapping to map from the source code of the template to the in-memory representation.

func NewPosition

func NewPosition() Position

NewPosition initialises a position.

func NewPositionFromInput

func NewPositionFromInput(pi parse.Input) Position

NewPositionFromInput creates a position from a parse input.

func NewPositionFromValues

func NewPositionFromValues(index int64, line, col int) Position

NewPositionFromValues initialises a position.

func (Position) String

func (p Position) String() string

type Range

type Range struct {
	From Position
	To   Position
}

Range of text within a file.

func NewRange

func NewRange(from, to Position) Range

NewRange creates a range.

type SafeCSS added in v0.0.113

type SafeCSS string

SafeCSS is CSS that has been sanitized.

func SanitizeCSS added in v0.0.113

func SanitizeCSS(property, value string) SafeCSS

SanitizeCSS sanitizes CSS properties to ensure that they are safe.

type SafeURL added in v0.0.113

type SafeURL string

SafeURL is a URL that has been sanitized.

func URL added in v0.0.113

func URL(s string) SafeURL

URL sanitizes the input string s and returns a SafeURL.

type SourceExpressionTo

type SourceExpressionTo struct {
	Source Expression
	Target Range
}

SourceExpressionTo is a record of an expression, along with its start and end positions.

type SourceMap

type SourceMap struct {
	Items []SourceExpressionTo
}

func NewSourceMap

func NewSourceMap() *SourceMap

NewSourceMap creates a new lookup to map templ source code to items in the parsed template.

func (*SourceMap) Add

func (sm *SourceMap) Add(src Expression, tgt Range) (updatedFrom Position)

Add an item to the lookup.

func (*SourceMap) SourcePositionFromTarget

func (sm *SourceMap) SourcePositionFromTarget(line, col int) (src Position, mapping SourceExpressionTo, ok bool)

SourcePositionFromTarget looks the source position using the target position.

func (*SourceMap) TargetPositionFromSource

func (sm *SourceMap) TargetPositionFromSource(line, col int) (tgt Position, mapping SourceExpressionTo, ok bool)

TargetPositionFromSource looks up the target position using the source position.

type StringExpression

type StringExpression struct {
	Expression Expression
}

StringExpression is used within HTML elements, and for style values. {%= ... %}

func (StringExpression) IsNode

func (se StringExpression) IsNode() bool

func (StringExpression) IsStyleDeclarationValue added in v0.0.113

func (se StringExpression) IsStyleDeclarationValue() bool

func (StringExpression) Write

func (se StringExpression) Write(w io.Writer, indent int) error

type StringSet added in v0.0.113

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

StringSet is a set of strings.

func RenderedCSSClassesFromContext added in v0.0.113

func RenderedCSSClassesFromContext(ctx context.Context) (context.Context, *StringSet)

RenderedCSSClassesFromContext returns a set of the CSS classes that have already been rendered to the response.

func (*StringSet) Add added in v0.0.113

func (rc *StringSet) Add(s string)

Add string s to the set.

func (*StringSet) All added in v0.0.113

func (rc *StringSet) All() (values []string)

All returns a slice of all items in the set.

func (*StringSet) Contains added in v0.0.113

func (rc *StringSet) Contains(s string) bool

Contains returns true if s is within the set.

type SwitchExpression

type SwitchExpression struct {
	Expression Expression
	Cases      []CaseExpression
	Default    []Node
}

{% switch p.Type %}

{% case "Something" %}
{% endcase %}

{% endswitch %}

func (SwitchExpression) IsNode

func (se SwitchExpression) IsNode() bool

func (SwitchExpression) Write

func (se SwitchExpression) Write(w io.Writer, indent int) error

type TemplateFile

type TemplateFile struct {
	Package Package
	Imports []Import
	Nodes   []TemplateFileNode
}

func Parse

func Parse(fileName string) (TemplateFile, error)

func ParseString

func ParseString(template string) (TemplateFile, error)

func (TemplateFile) Write

func (tf TemplateFile) Write(w io.Writer) error

type TemplateFileNode added in v0.0.113

type TemplateFileNode interface {
	IsTemplateFileNode() bool
	Write(w io.Writer, indent int) error
}

TemplateFileNode can be a Template or a CSS.

type TemplateFileParser

type TemplateFileParser struct {
}

func NewTemplateFileParser

func NewTemplateFileParser() TemplateFileParser

NewTemplateFileParser creates a new TemplateFileParser.

func (TemplateFileParser) Parse

type Whitespace

type Whitespace struct {
	Value string
}

Whitespace.

func (Whitespace) IsNode

func (ws Whitespace) IsNode() bool

func (Whitespace) Write

func (ws Whitespace) Write(w io.Writer, indent int) error

Jump to

Keyboard shortcuts

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