The world’s most powerful template engine and Go embeddable interpreter.

Scriggo

The world’s most powerful template engine and Go embeddable interpreter.

Go Reference Go Report Card

Website | Get Started | Documentation | Community | Contributing

Features

  • Fast, a very fast embeddable pure Go language interpreter.
  • Modern and powerful template engine with Go as scripting language.
  • Native support for Markdown in templates.
  • Secure by default. No access to packages unless explicitly enabled.
  • Easy to embed and to interop with any Go application.

Get Started with Programs

Execute a Go program embedded in your application:

package main

import "github.com/open2b/scriggo"

func main() {

    // src is the source code of the program to run.
    src := []byte(`
        package main

        func main() {
            println("Hello, World!")
        }
    `)

    // Create a file system with the file of the program to run.
    fsys := scriggo.Files{"main.go": src}

    // Build the program.
    program, err := scriggo.Build(fsys, nil)
    if err != nil {
        panic(err)
    }
 
    // Run the program.
    err = program.Run(nil)
    if err != nil {
        panic(err)
    }

}

Get Started with Templates

Scriggo, in templates, supports inheritance, macros, partials, imports and contextual autoescaping but most of all it uses the Go language as the template scripting language.

{% for product in products %}
  • {{ product.Name }}
  • {% end %} {{ render "pagination.html" }} {{ Banner() }} {% end %} ">
    {% extends "layout.html" %}
    {% import "banners.html" %}
    {% macro Body %}
        
       
        {{ render "pagination.html" }}
        {{ Banner() }}
    {% end %}
    

    Scriggo template files can be written in plain text, HTML, Markdown, CSS, JavaScript and JSON.

    Execute a Scriggo template in your application

    Hello {% who := "World" %} Hello, {{ who }}! `) // Create a file system with the file of the template to run. fsys := scriggo.Files{"index.html": content} // Build the template. template, err := scriggo.BuildTemplate(fsys, "index.html", nil) if err != nil { panic(err) } // Run the template and print it to the standard output. err = template.Run(os.Stdout, nil, nil) if err != nil { panic(err) } } ">
    // Build and run a Scriggo template.
    package main
    
    import (
        "os"
        "github.com/open2b/scriggo"
    )
    
    func main() {
    
        // Content of the template file to run.
        content := []byte(`
        
        
        Hello 
        
            {% who := "World" %}
            Hello, {{ who }}!
        
        
        `)
    
        // Create a file system with the file of the template to run.
        fsys := scriggo.Files{"index.html": content}
    
        // Build the template.
        template, err := scriggo.BuildTemplate(fsys, "index.html", nil)
        if err != nil {
            panic(err)
        }
     
        // Run the template and print it to the standard output.
        err = template.Run(os.Stdout, nil, nil)
        if err != nil {
            panic(err)
        }
    
    }

    For a complete get started guide see the Scriggo site.

    Contributing

    Want to help contribute to Scriggo? See CONTRIBUTING.md.

    Comments
    • compiler: change a struct field of a pointer value causes an invalid behavior

      compiler: change a struct field of a pointer value causes an invalid behavior

      Executing the following code, it prints "a" instead of "b"

      package main
      
      import "pkg"
      
      func main() {
      	a := &pkg.T{A: "a"}
      	a.A = "b"
      	print(a.A)
      }
      
    • compiler: panic emitting a func/macro that references to a parameter of an outer func/macro

      compiler: panic emitting a func/macro that references to a parameter of an outer func/macro

      This code

      {% macro Dialog(title string, content macro() html) %}
      <div class="dialog">
          <header>{{ title }}</header>
          <section>
              {{ content() }}
          </section>
      </div>
      {% end %}
      
      {% macro ButtonDialog(title, buttonText string) %}
      {% macro content %}
      <div>Press the button</div>
      <button>{{ buttonText }}</button>
      {% end %}
      {{ Dialog(title, content) }}
      {% end %}
      
      {{ ButtonDialog("Press the button dialog", "Play") }}
      

      panics the emitter with BUG: not supported.

    • vm: run-time panics

      vm: run-time panics

      This issue is for tracking and discussing the run-time panics implementation as described in the Go specs.

      The test https://github.com/open2b/scriggo/blob/master/test/compare/testdata/misc/runtime_panic.go tests all the run-time panics.

    • compiler: declaration of struct types with unexported fields

      compiler: declaration of struct types with unexported fields

      I campi non esportati delle strutture definite in Scrigo portano all'errore:

      reflect.StructOf: field "f1" is unexported but missing PkgPath
      

      dove S è definita come

      type F1 struct { A int }
      type F2 int
      type S struct {
      	f1 F1
      	f2 F2
      }
      
    • Runtime panic with IncDec statements and assignment operators involving pointers

      Runtime panic with IncDec statements and assignment operators involving pointers

      EDIT: the issue related to the source code in this comment has been moved to a separate issue, the #921. The rest of the tests on this discussion refer to a different issue (related to the emitter) that has been solved.

      Source code

      package main
      
      import "fmt"
      
      var P = new(int)
      
      func main() {
              fmt.Println(*P)
              *P = 32
              fmt.Println(*P)
              *P++
              fmt.Println(*P)
      }
      
      

      Scriggo output

      0
      32
      4
      

      gc output

      0
      32
      33
      
    • compiler/checker: panic on build when using import rename

      compiler/checker: panic on build when using import rename

      When a package is imported using the AS keyword to change the import path scriggo does not detect that the package name is not the path. This allows the script to reference the wrong package name and panic the program during the Build call.

      Scriggo command and library version: scriggo version v0.53.1 (go1.16.7)

      The Scriggofile

      SET PACKAGE main
      SET VARIABLE packages
      GOOS linux
      
      IMPORT github.com/google/uuid
      IMPORT github.com/3dsinteractive/uuid as foobar
      

      The main.go file

      package main
      
      import (
              "github.com/open2b/scriggo"
              "github.com/open2b/scriggo/native"
      )
      
      var packages native.Packages
      
      func main() {
      
              // src is the source code of the program to run.
              src := []byte(`
              package main
      
              import (
                      "github.com/google/uuid"
                      "foobar"
              )
      
              func main() {
                  println(uuid.New().String())
                  println(foobar.New().String())
              }
          `)
      
              // Create a file system with the file of the program to run.
              fsys := scriggo.Files{"main.go": src}
      
              // Use the importer in the packages variable.
              opts := &scriggo.BuildOptions{Packages: packages}
      
              // Build the program.
              program, err := scriggo.Build(fsys, opts)
              if err != nil {
                      panic(err)
              }
      
              // Run the program.
              if err = program.Run(nil); err != nil {
                      panic(err)
              }
      }
      

      The panic

      panic: runtime error: invalid memory address or nil pointer dereference [recovered]
              panic: runtime error: invalid memory address or nil pointer dereference
      [signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x5582c5]
      
      goroutine 1 [running]:
      github.com/open2b/scriggo/internal/compiler.checkPackage.func1(0xc00014bb80)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/checker_package.go:523 +0x8d
      panic(0x6e0100, 0x8f5290)
              /opt/go/go/src/runtime/panic.go:965 +0x1b9
      github.com/open2b/scriggo/ast.(*Identifier).Pos(0x0, 0x6edfe0)
              <autogenerated>:1 +0x5
      github.com/open2b/scriggo/internal/compiler.checkError(0x71b1eb, 0x4, 0x6edfe0, 0x0, 0xc000068070, 0x64, 0x0, 0x0, 0x0, 0x4, ...)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/checker.go:350 +0x1a3
      github.com/open2b/scriggo/internal/compiler.(*typechecker).errorf(...)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/checker.go:344
      github.com/open2b/scriggo/internal/compiler.(*typechecker).assignScope(0xc00014c000, 0x71b377, 0x4, 0xc0001517a0, 0x0, 0xc000026240)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/checker.go:264 +0x590
      github.com/open2b/scriggo/internal/compiler.(*typechecker).checkImport(0xc00014c000, 0xc000026240, 0x0, 0x0)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/checker_statements.go:1020 +0x1b57
      github.com/open2b/scriggo/internal/compiler.checkPackage(0xc000119180, 0xc0000261c0, 0x71b1eb, 0x4, 0x78bb20, 0xc00007e690, 0x1, 0x0, 0x0, 0x0, ...)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/checker_package.go:572 +0x11eb
      github.com/open2b/scriggo/internal/compiler.typecheck(0xc000026180, 0x78bb20, 0xc00007e690, 0x1, 0x0, 0x0, 0x0, 0x0, 0x418f7e, 0x7fbfb08ef300, ...)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/checker.go:47 +0xffa
      github.com/open2b/scriggo/internal/compiler.BuildProgram(0x78ba80, 0xc00007e720, 0x0, 0x0, 0x0, 0x78bb20, 0xc00007e690, 0x0, 0x0, 0x8ff160, ...)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/compiler/compiler.go:140 +0x11d
      github.com/open2b/scriggo.Build(0x78ba80, 0xc00007e720, 0xc000053f38, 0x7, 0xc000126088, 0xc000000180)
              /home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/programs.go:98 +0xd9
      

      Note

      If the script sets the package name then the program executes normally

      e.g. import foobar "foobar"

    • Runtime panic using a global within imported nested macro

      Runtime panic using a global within imported nested macro

      Given this test:

      "https://github.com/open2b/scriggo/issues/768": {
      	sources: map[string]string{
      		"index.html":   `{% _ = render "partial.html" %}`,
      		"partial.html": `{% macro m %}{% _ = page %}{% end %}{{ m() }}`,
      	},
      	main: scriggo.MapPackage{
      		PkgName: "main",
      		Declarations: map[string]interface{}{
      			"page": &([]string{"a"})[0],
      		},
      	},
      	expectedOut: "",
      },
      

      panics the runtime

      case OpGetVar:
      	v := vm.vars[decodeInt16(a, b)]  // <-- index out of range [0] with length 0
      	vm.setFromReflectValue(c, v)
      
      
    • proposal: templates: extend the show statement with the

      proposal: templates: extend the show statement with the "default" form

      I propose to extend the show statement with this form

      show m(x1, x2, ...) default e1, e2, ..., en
      

      where m is an identifier. If m is defined, it is the same of

      show m(x1, x2, ...)
      

      otherwise it is the same of

      show e1, e2, ..., en
      

      If m is defined but is not a function (or macro), a compile-time error occurs.

      This form can be also used between {{ and }}

      {{ m(x1, x2, ...) default e1, e2, ..., en }}
      

      The blank identifier can not be used as default expression, an empty string can be used to indicate that there is nothing to show. For example

      {{ Head() default "" }}
      

      Syntax

      "show" ( ExpressionList | identifier Arguments "default" ExpressionList )
      
      "{{" ( Expression | identifier Arguments "default" ExpressionList ) "}}"
      
    • compiler: cannot assign function literals to indirect variables

      compiler: cannot assign function literals to indirect variables

      Il codice

      package main
      
      import (
            "fmt"
      )
      
      func main() {
            A := 10
            B := 20
            f1 := func() {
                  fmt.Print(A)
                  A = 10
            }
            f2 := func() {
                  f1()
                  fmt.Print(B)
                  A = B + 2
            }
            f3 := func() {
                  fmt.Print(A + B)
                  B = A + B
            }
            f1()
            f2()
            f3()
      }
      

      va in panic value of type *vm.callable is not assignable to type func().

      Il problema si presenta nel caso della chiamata ad f1 dentro il corpo di f2

    • proposal: allow accessing map keys like fields in templates

      proposal: allow accessing map keys like fields in templates

      Also, allow implicit cast from interface{} to map[string]interface{} or map[string]T on indexing.

      So, I want following to be possible:

      {{ data.foo.bar.key }}
      

      Instead of:

      {{ data["foo"].(map[string]interface{})["bar"].(map[string]interface{})["key"] }}
      

      Full test example:

      package maps_test
      
      import (
      	"bytes"
      	"testing"
      
      	"github.com/open2b/scriggo"
      	"github.com/open2b/scriggo/native"
      	"github.com/stretchr/testify/require"
      	"gopkg.in/yaml.v3"
      )
      
      func TestMap(t *testing.T) {
      	var data map[string]interface{}
      	require.NoError(t, yaml.Unmarshal([]byte(`---
      foo:
        bar:
          key: "value"
          number: 1
      `), &data))
      	for _, tt := range []struct {
      		Name  string
      		Value string
      	}{
      		{
      			Name:  "Explicit",
      			Value: `{{ data["foo"].(map[string]interface{})["bar"].(map[string]interface{})["key"] }}`,
      		},
      		{
      			Name:  "Implicit",
      			Value: `{{ data.foo.bar.key }}`,
      		},
      	} {
      		t.Run(tt.Name, func(t *testing.T) {
      			fsys := scriggo.Files{"index.html": []byte(tt.Value)}
      			opts := &scriggo.BuildOptions{
      				Globals: native.Declarations{"data": &data},
      			}
      			template, err := scriggo.BuildTemplate(fsys, "index.html", opts)
      			require.NoError(t, err)
      
      			b := new(bytes.Buffer)
      			require.NoError(t, template.Run(b, nil, nil))
      		})
      	}
      }
      
      index.html:1:8: data.foo undefined (type map[string]interface {} has no field or method foo)
      
    • compiler,runtime: panic in case of Scriggo type as map key when calling builtin 'delete'

      compiler,runtime: panic in case of Scriggo type as map key when calling builtin 'delete'

      cannot delete from a map when the key is a complex type.

      Consider the following snippet:

      package main
      
      type key struct {
              X int
              Y int
      }
      
      func main() {
              println("starting population")
              mpbasic := map[int]int{}
              mpcomplex := map[key]int{}
              for i := 0; i < 256; i++ {
                      mpbasic[i] = i * 2
                      mpcomplex[key{X: i, Y: i + 1}] = i * 2
              }
              println("starting delete simple")
              for k := range mpbasic {
                      delete(mpbasic, k)
              }
              println("starting delete complex")
              for k := range mpcomplex {
                      if mpcomplex[k] > 2 {
                              delete(mpcomplex, k)
                      }
              }
              println("done")
      }
      

      When run using the GC we get the following output (runs to completion):

      starting population
      starting delete simple
      starting delete complex
      done
      

      When run using scriggo we get the following output with a panic:

      panic: reflect.Value.SetMapIndex: value of type types.emptyInterfaceProxy is not assignable to type struct { X int; Y int }
      
      goroutine 1 [running]:
      github.com/open2b/scriggo/internal/runtime.(*VM).Run(0xc0000e4240, 0xc0000a5520, 0xc00009e970, 0x0, 0x0, 0x0, 0x0, 0x0)
      	/home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/internal/runtime/vm.go:161 +0x169
      github.com/open2b/scriggo.(*Program).Run(0xc0000a1380, 0x0, 0x0, 0xc0000a1380)
      	/home/kris/mygo/pkg/mod/github.com/open2b/[email protected]/programs.go:143 +0xd6
      main.main()
      	/tmp/scriggo_test/main.go:19 +0x13f
      

      I am building off of the tip of master (commit 8c493a4aa1f8014e3f10a9e447b3ab45ab71967f)

      It appears that the range iterator on a map hands back some sort of pointer when using complex map key types, but the delete function cannot handle that pointer. Using native types for the key this completes fine.

      Complete test program

      package main
      
      import (
              "fmt"
      
              "github.com/open2b/scriggo"
      )
      
      func main() {
              // Create a file system with the file of the program to run.
              fsys := scriggo.Files{"main.go": []byte(src)}
      
              // Build the program.
              program, err := scriggo.Build(fsys, nil)
              if err != nil {
                      panic(err)
              }
              // Run the program.
              err = program.Run(nil)
              if err != nil {
                      fmt.Println("RUN ERROR", err)
              }
              fmt.Println("DONE")
      }
      
      const src = `
              package main
      
              type key struct {
                      X int
                      Y int
              }
      
              func main() {
                  println("starting population")
                  mpbasic := map[int]int{}
                  mpcomplex := map[key]int{}
                  for i := 0; i < 256; i++ {
                      mpbasic[i] = i*2
                      mpcomplex[key{X: i, Y: i+1}] = i*2
                  }
                  println("starting delete simple")
                  for k := range mpbasic {
                      delete(mpbasic, k)
                  }
                  println("starting delete complex")
                  for k := range mpcomplex {
                      if mpcomplex[k] > 2 {
                              delete(mpcomplex, k)
                      }
                  }
                  println("done")
              }
      
      `
      
    • compiler/checker: the compiler panics instead of returning a type-checking error with invalid default statement

      compiler/checker: the compiler panics instead of returning a type-checking error with invalid default statement

      Consider this test:

      "https://github.com/open2b/scriggo/issues/941": {
      	sources: fstest.Files{
      		"index.html": `{% var filters = filters default nil %}`,
      	},
      	main: native.Package{
      		Name: "main",
      		Declarations: native.Declarations{
      			"filters": (*[]int)(nil),
      		},
      	},
      },
      

      instead of returning an error relative to the use of the untyped nil, it panics the type checker.

      Note that this code:

      "https://github.com/open2b/scriggo/issues/941": {
      	sources: fstest.Files{
      		"index.html": `{% var filters = filters default nil %}`,
      	},
      	expectedBuildErr: "use of untyped nil",
      },
      

      works as expected. The problem seems to be related to this code:

      https://github.com/open2b/scriggo/blob/aeab4b833a0de2895dd3874f296fd3f805898f8d/internal/compiler/checker_assignment.go#L401-L413

    • Runtime panic in template related to defer (needs investigation)

      Runtime panic in template related to defer (needs investigation)

      How to reproduce

      Add this test to test/misc/templates_test.go:

      "https://github.com/open2b/scriggo/issues/936": {
      	sources: fstest.Files{
      		"index.txt": `
      			{% var f = func() []int {
      				defer func() { }()
      				return []int{}
      			} %}
      	
      			{% for v in f() %}
      			{% end for %}
      	
      			Some text`,
      	},
      },
      
    • Some variables are reported more than once by method 'Template.UsedVars'

      Some variables are reported more than once by method 'Template.UsedVars'

      Some variables are reported more than once by method 'Template.UsedVars'. For example, a call to such method returned this:

      ...
      "appliedFilters",
      "appliedFilters",
      "banners",
      "banners",
      "banners",
      ...
      "customerFirstName",
      "customerFirstName",
      "departments",
      "departments",
      ...
      "filters",
      "filters",
      ...
      "isLoggedIn",
      "isLoggedIn",
      ...
      "menus",
      "menus",
      "menus",
      ...
      "page",
      "page",
      ...
      

      Investigate about this.

    • compiler/parser: invalid behaviour with struct composite literals

      compiler/parser: invalid behaviour with struct composite literals

      Consider this code:

      package main
      
      type T struct { A, B int}
      
      func main() {
      	_ =  T{
      		A: 10,
      		B: 20
      	}
      }
      

      The parser should return error:

      syntax error: unexpected newline, expecting comma or }
      

      but, instead, it accepts the code as it is correct.

      Note that the same problem also involves the templates (add this test to test/misc/templates_test.go):

      "BUG": {
      	sources: fstest.Files{
      		"index.html": `{%%
      			_ = struct{A, B int} {
      				A: 1,
      				B: 2
      			}
      			%%}
      		`,
      	},
      },
      
    • compiler/checker: invalid convertion from 'html' to 'string' in return statement

      compiler/checker: invalid convertion from 'html' to 'string' in return statement

      If an alias of the html type is used as global in templates:

      var globals = native.Declarations{
      	"HTML": reflect.TypeOf((*native.HTML)(nil)).Elem(),
      }
      

      Scriggo does not check that a typed string value cannot be converted to that type, for example this code does not fail:

      {% var s = "a" %}
      {{ HTML(s) }}
      
    • "reflect.Value.Slice3: slice of unaddressable array" when slicing arrays when iterating over maps

      This code:

      package main
      
      func main() {
      
      	m := map[string][3]int{}
      	m["x"] = [3]int{10, 20, 30}
      
      	for _, v := range m {
      		s := v[:]
      		_ = s
      	}
      
      }
      

      should be valid, but it panics the Scriggo runtime with this error:

      reflect.Value.Slice3: slice of unaddressable array
      

      Note that this issue may be partially related to #376.

    A handy, fast and powerful go template engine.
    A handy, fast and powerful go template engine.

    Hero Hero is a handy, fast and powerful go template engine, which pre-compiles the html templates to go code. It has been used in production environme

    Dec 27, 2022
    ⚗ The most advanced CLI template on earth! Featuring automatic releases, website generation and a custom CI-System out of the box.
    ⚗ The most advanced CLI template on earth! Featuring automatic releases, website generation and a custom CI-System out of the box.

    cli-template ✨ ⚗ A template for beautiful, modern, cross-platform compatible CLI tools written with Go! Getting Started | Wiki This template features

    Dec 4, 2022
    The powerful template system that Go needs

    Plush Plush is the templating system that Go both needs and deserves. Powerful, flexible, and extendable, Plush is there to make writing your template

    Dec 29, 2022
    Goview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application.

    goview Goview is a lightweight, minimalist and idiomatic template library based on golang html/template for building Go web application. Contents Inst

    Dec 25, 2022
    Simple system for writing HTML/XML as Go code. Better-performing replacement for html/template and text/template

    Simple system for writing HTML as Go code. Use normal Go conditionals, loops and functions. Benefit from typing and code analysis. Better performance than templating. Tiny and dependency-free.

    Dec 5, 2022
    A template to build dynamic web apps quickly using Go, html/template and javascript
    A template to build dynamic web apps quickly using Go, html/template and javascript

    gomodest-template A modest template to build dynamic web apps in Go, HTML and sprinkles and spots of javascript. Why ? Build dynamic websites using th

    Dec 29, 2022
    Wrapper package for Go's template/html to allow for easy file-based template inheritance.

    Extemplate Extemplate is a small wrapper package around html/template to allow for easy file-based template inheritance. File: templates/parent.tmpl <

    Dec 6, 2022
    Made from template temporalio/money-transfer-project-template-go
    Made from template temporalio/money-transfer-project-template-go

    Temporal Go Project Template This is a simple project for demonstrating Temporal with the Go SDK. The full 20 minute guide is here: https://docs.tempo

    Jan 6, 2022
    Go-project-template - Template for a golang project

    This is a template repository for golang project Usage Go to github: https://git

    Oct 25, 2022
    Go-api-template - A rough template to give you a starting point for your API

    Golang API Template This is only a rough template to give you a starting point f

    Jan 14, 2022
    Api-go-template - A simple Go API template that uses a controller-service based model to build its routes

    api-go-template This is a simple Go API template that uses a controller-service

    Feb 18, 2022
    Simple and fast template engine for Go

    fasttemplate Simple and fast template engine for Go. Fasttemplate performs only a single task - it substitutes template placeholders with user-defined

    Dec 30, 2022
    HTML template engine for Go

    Ace - HTML template engine for Go Overview Ace is an HTML template engine for Go. This is inspired by Slim and Jade. This is a refinement of Gold. Exa

    Jan 4, 2023
    Jet template engine

    Jet Template Engine for Go Jet is a template engine developed to be easy to use, powerful, dynamic, yet secure and very fast. simple and familiar synt

    Jan 4, 2023
    A complete Liquid template engine in Go
    A complete Liquid template engine in Go

    Liquid Template Parser liquid is a pure Go implementation of Shopify Liquid templates. It was developed for use in the Gojekyll port of the Jekyll sta

    Dec 15, 2022
    gtpl is a template engine for glang

    gtpl 使用必读 gtpl is a HTML template engine for golang gtpl 是一个 go 语言模板引擎,它能以极快的速度进行模板语法分析。相比 go 语言官方库 html/template,gtpl 的语法有着简练、灵活、易用的特点。

    Nov 28, 2022
    This my project template for making fiber with SSR taste by empowered mustache engine.

    SSR-FIBER-TEMPLATE This my project template for making fiber with SSR taste by empowered mustache engine. Folder Hierarchy Name Description configs Co

    May 9, 2022
    Package damsel provides html outlining via css-selectors and common template functionality.

    Damsel Markup language featuring html outlining via css-selectors, extensible via pkg html/template and others. Library This package expects to exist

    Oct 23, 2022
    A sane and simple Go REST API template.

    Gosane ??‍♀️ A sane and simple Go REST API template. Clone me and edit me to fit your usecase. What is Gosane? Gosane is a cloneable API template to g

    Dec 7, 2022