├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── _examples
├── iris_multi
│ ├── main.go
│ └── templates
│ │ ├── hiAMBER.amber
│ │ └── hiHTML.html
├── nethttp_html
│ ├── main.go
│ └── templates
│ │ ├── layouts
│ │ └── layout.html
│ │ └── mypage.html
└── nethttp_multi
│ ├── main.go
│ └── templates
│ ├── hiAMBER.amber
│ └── hiHTML.html
├── amber
├── README.md
├── amber.go
└── config.go
├── django
├── README.md
├── config.go
└── django.go
├── engine.go
├── handlebars
├── README.md
├── config.go
└── handlebars.go
├── html
├── README.md
├── config.go
└── html.go
├── loader.go
├── logo.jpg
├── markdown
├── README.md
├── config.go
└── markdown.go
├── mux.go
├── pug
├── README.md
├── config.go
└── pug.go
├── template.go
└── vendor
└── github.com
├── Joker
└── jade
│ ├── LICENSE.md
│ ├── config.go
│ ├── jade_lex.go
│ ├── jade_node.go
│ ├── jade_parse.go
│ ├── lex.go
│ ├── node.go
│ ├── parse.go
│ └── template.go
├── aymerick
└── raymond
│ ├── LICENSE
│ ├── VERSION
│ ├── ast
│ ├── node.go
│ └── print.go
│ ├── data_frame.go
│ ├── escape.go
│ ├── eval.go
│ ├── handlebars
│ └── doc.go
│ ├── helper.go
│ ├── lexer
│ ├── lexer.go
│ └── token.go
│ ├── mustache
│ ├── Changes
│ ├── Rakefile
│ ├── TESTING.md
│ └── specs
│ │ ├── comments.json
│ │ ├── comments.yml
│ │ ├── delimiters.json
│ │ ├── delimiters.yml
│ │ ├── interpolation.json
│ │ ├── interpolation.yml
│ │ ├── inverted.json
│ │ ├── inverted.yml
│ │ ├── partials.json
│ │ ├── partials.yml
│ │ ├── sections.json
│ │ ├── sections.yml
│ │ ├── ~lambdas.json
│ │ └── ~lambdas.yml
│ ├── parser
│ ├── parser.go
│ └── whitespace.go
│ ├── partial.go
│ ├── raymond.go
│ ├── string.go
│ ├── template.go
│ └── utils.go
├── eknkc
└── amber
│ ├── amberc
│ └── cli.go
│ ├── compiler.go
│ ├── parser
│ ├── nodes.go
│ ├── parser.go
│ └── scanner.go
│ └── runtime.go
├── flosch
└── pongo2
│ ├── AUTHORS
│ ├── LICENSE
│ ├── context.go
│ ├── doc.go
│ ├── error.go
│ ├── filters.go
│ ├── filters_builtin.go
│ ├── helpers.go
│ ├── lexer.go
│ ├── nodes.go
│ ├── nodes_html.go
│ ├── nodes_wrapper.go
│ ├── parser.go
│ ├── parser_document.go
│ ├── parser_expression.go
│ ├── pongo2.go
│ ├── tags.go
│ ├── tags_autoescape.go
│ ├── tags_block.go
│ ├── tags_comment.go
│ ├── tags_cycle.go
│ ├── tags_extends.go
│ ├── tags_filter.go
│ ├── tags_firstof.go
│ ├── tags_for.go
│ ├── tags_if.go
│ ├── tags_ifchanged.go
│ ├── tags_ifequal.go
│ ├── tags_ifnotequal.go
│ ├── tags_import.go
│ ├── tags_include.go
│ ├── tags_lorem.go
│ ├── tags_macro.go
│ ├── tags_now.go
│ ├── tags_set.go
│ ├── tags_spaceless.go
│ ├── tags_ssi.go
│ ├── tags_templatetag.go
│ ├── tags_widthratio.go
│ ├── tags_with.go
│ ├── template.go
│ ├── template_loader.go
│ ├── template_sets.go
│ ├── value.go
│ └── variable.go
├── juju
└── errors
│ ├── LICENSE
│ ├── Makefile
│ ├── doc.go
│ ├── error.go
│ ├── errortypes.go
│ ├── functions.go
│ └── path.go
├── kataras
└── go-errors
│ ├── LICENSE
│ └── errors.go
├── microcosm-cc
└── bluemonday
│ ├── LICENCE.md
│ ├── Makefile
│ ├── cmd
│ ├── sanitise_html_email
│ │ ├── doc.go
│ │ └── main.go
│ └── sanitise_ugc
│ │ ├── doc.go
│ │ └── main.go
│ ├── doc.go
│ ├── helpers.go
│ ├── policies.go
│ ├── policy.go
│ └── sanitize.go
├── russross
└── blackfriday
│ ├── LICENSE.txt
│ ├── README.md
│ ├── block.go
│ ├── html.go
│ ├── inline.go
│ ├── latex.go
│ ├── markdown.go
│ └── smartypants.go
├── shurcooL
└── sanitized_anchor_name
│ ├── LICENSE
│ └── main.go
└── valyala
└── bytebufferpool
├── LICENSE
├── bytebuffer.go
├── bytebuffer_test.go
└── pool.go
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .settings/*
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - go1.7
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Gerasimos Maropoulos
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/_examples/iris_multi/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "gopkg.in/kataras/iris.v6"
5 | "gopkg.in/kataras/iris.v6/adaptors/httprouter"
6 | "gopkg.in/kataras/iris.v6/adaptors/view"
7 | )
8 |
9 | type mypage struct {
10 | Title string
11 | Message string
12 | }
13 |
14 | func main() {
15 | app := iris.New()
16 | app.Adapt(iris.DevLogger())
17 | app.Adapt(httprouter.New())
18 |
19 | // the html engine on ./templates folder compile all *.html files
20 | app.Adapt(view.HTML("./templates", ".html"))
21 |
22 | // add our second template engine with the same directory but with .amber file extension
23 | app.Adapt(view.Amber("./templates", ".amber"))
24 |
25 | app.Get("/render_html", func(ctx *iris.Context) {
26 | ctx.RenderWithStatus(iris.StatusOK, "hiHTML.html", map[string]interface{}{"Name": "You!"})
27 | })
28 |
29 | app.Get("/render_amber", func(ctx *iris.Context) {
30 | ctx.MustRender("hiAMBER.amber", map[string]interface{}{"Name": "You!"})
31 | })
32 |
33 | println("Open a browser tab & go to localhost:8080/render_html & localhost:8080/render_amber")
34 | app.Listen(":8080")
35 | }
36 |
37 | // More can be found there:
38 | // https://github.com/iris-contrib/examples/tree/master/template_engines
39 |
--------------------------------------------------------------------------------
/_examples/iris_multi/templates/hiAMBER.amber:
--------------------------------------------------------------------------------
1 | !!! 5
2 | html
3 | head
4 | title Hello Amber from Go-Template
5 |
6 | meta[name="description"][value="This is a sample"]
7 |
8 | script[type="text/javascript"]
9 | var hw = "Hello #{Name}!"
10 | alert(hw)
11 |
12 | style[type="text/css"]
13 | body {
14 | background: maroon;
15 | color: white
16 | }
17 |
18 | body
19 | header#mainHeader
20 | ul
21 | li.active
22 | a[href="/"] Main Page
23 | [title="Main Page"]
24 | h1
25 | | Hi #{Name}
26 |
27 | footer
28 | | Hey
29 | br
30 | | There
31 |
--------------------------------------------------------------------------------
/_examples/iris_multi/templates/hiHTML.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hi
4 |
5 |
6 | Hi {{.Name}}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/_examples/nethttp_html/main.go:
--------------------------------------------------------------------------------
1 | // Package main is a small example for html/template, same for all other
2 | package main
3 |
4 | import (
5 | "net/http"
6 |
7 | "github.com/kataras/go-template"
8 | "github.com/kataras/go-template/html"
9 | )
10 |
11 | type mypage struct {
12 | Title string
13 | Message string
14 | }
15 |
16 | func main() {
17 | // create our html template engine, using a Layout
18 | tmplEngine := html.New(html.Config{Layout: "layouts/layout.html"})
19 |
20 | loader := template.NewLoader()
21 | loader.Directory("./templates", ".html") // defaults
22 | // for binary assets:
23 | // loader.Directory(dir string, ext string).Binary(assetFn func(name string) ([]byte, error), namesFn func() []string)
24 |
25 | // load the templates inside ./templates with extension .html
26 | //using the html template engine
27 | err := loader.LoadEngine(tmplEngine)
28 | if err != nil {
29 | panic("While parsing the template files: " + err.Error())
30 | }
31 |
32 | http.Handle("/", http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
33 | // first parameter the writer
34 | // second parameter any page context (look ./templates/mypage.html) and you will understand
35 | // third parameter is optionally, is a map[string]interface{}
36 | // which you can pass a "layout" to change the layout for this specific render action
37 | // or the "charset" to change the defaults which is "utf-8"
38 | err := tmplEngine.ExecuteWriter(res, "mypage.html", mypage{"My Page title", "Hello world!"})
39 | if err != nil {
40 | res.Write([]byte(err.Error()))
41 | }
42 | }))
43 |
44 | println("Open a browser tab & go to localhost:8080")
45 | http.ListenAndServe(":8080", nil)
46 | }
47 |
--------------------------------------------------------------------------------
/_examples/nethttp_html/templates/layouts/layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | My Layout
4 |
5 |
6 |
7 | Body is:
8 |
9 | {{ yield }}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/_examples/nethttp_html/templates/mypage.html:
--------------------------------------------------------------------------------
1 |
2 | Title: {{.Title}}
3 |
4 | Message: {{.Message}}
5 |
--------------------------------------------------------------------------------
/_examples/nethttp_multi/main.go:
--------------------------------------------------------------------------------
1 | // Package main uses the template.Mux here to simplify the steps
2 | // and support of loading more than one template engine for a single app
3 | // you can do the same things without the Mux, as you saw on the /html example folder
4 | package main
5 |
6 | import (
7 | "net/http"
8 |
9 | "github.com/kataras/go-template"
10 | "github.com/kataras/go-template/amber"
11 | "github.com/kataras/go-template/html"
12 | )
13 |
14 | type mypage struct {
15 | Title string
16 | Message string
17 | }
18 |
19 | func main() {
20 | // templates := template.NewMux()
21 | // templates.AddEngine(tmplEngine).Directory("./templates", ".html") // the defaults
22 | // or just use the default package-level mux
23 | // defaults to dir "./templates" and ".html" as extension, you can change it by .Directory("./mydir", ".html")
24 | template.AddEngine(html.New())
25 | // set our second template engine with the same directory but with .amber file extension
26 | template.AddEngine(amber.New()).Directory("./templates", ".amber")
27 |
28 | // load all the template files using the correct template engine for each one of the files
29 | err := template.Load()
30 | if err != nil {
31 | panic("While parsing the template files: " + err.Error())
32 | }
33 |
34 | http.Handle("/render_html", http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
35 | // first parameter the writer
36 | // second parameter any page context (look ./templates/mypage.html) and you will understand
37 | // third parameter is optionally, is a map[string]interface{}
38 | // which you can pass a "layout" to change the layout for this specific render action
39 | // or the "charset" to change the defaults which is "utf-8"
40 |
41 | // Does the same thing but returns the parsed template file results as string
42 | // useful when you want to send rich e-mails with a template
43 | // template.ExecuteString(name, pageContext, options...)
44 |
45 | err := template.ExecuteWriter(res, "hiHTML.html", map[string]interface{}{"Name": "You!"}) // yes you can pass simple maps instead of structs
46 | if err != nil {
47 | res.Write([]byte(err.Error()))
48 | }
49 | }))
50 |
51 | http.Handle("/render_amber", http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
52 | template.ExecuteWriter(res, "hiAMBER.amber", map[string]interface{}{"Name": "You!"})
53 | }))
54 |
55 | println("Open a browser tab & go to localhost:8080/render_html & localhost:8080/render_amber")
56 | http.ListenAndServe(":8080", nil)
57 | }
58 |
--------------------------------------------------------------------------------
/_examples/nethttp_multi/templates/hiAMBER.amber:
--------------------------------------------------------------------------------
1 | !!! 5
2 | html
3 | head
4 | title Hello Amber from Go-Template
5 |
6 | meta[name="description"][value="This is a sample"]
7 |
8 | script[type="text/javascript"]
9 | var hw = "Hello #{Name}!"
10 | alert(hw)
11 |
12 | style[type="text/css"]
13 | body {
14 | background: maroon;
15 | color: white
16 | }
17 |
18 | body
19 | header#mainHeader
20 | ul
21 | li.active
22 | a[href="/"] Main Page
23 | [title="Main Page"]
24 | h1
25 | | Hi #{Name}
26 |
27 | footer
28 | | Hey
29 | br
30 | | There
31 |
--------------------------------------------------------------------------------
/_examples/nethttp_multi/templates/hiHTML.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hi
4 |
5 |
6 | Hi {{.Name}}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/amber/README.md:
--------------------------------------------------------------------------------
1 | ## Folder information
2 |
3 | This folder contains the buit'n [amber](https://github.com/eknkc/amber) cross-framework template engine support.
4 |
--------------------------------------------------------------------------------
/amber/amber.go:
--------------------------------------------------------------------------------
1 | package amber
2 |
3 | import (
4 | "fmt"
5 | "html/template"
6 | "io"
7 | "path/filepath"
8 | "strings"
9 | "sync"
10 |
11 | "github.com/eknkc/amber"
12 | )
13 |
14 | // Engine the amber template engine
15 | type Engine struct {
16 | Config Config
17 | templateCache map[string]*template.Template
18 | mu sync.Mutex
19 | }
20 |
21 | // New creates and returns a new amber engine
22 | func New(cfg ...Config) *Engine {
23 | c := DefaultConfig()
24 | if len(cfg) > 0 {
25 | c = cfg[0]
26 | }
27 |
28 | // cuz mergo has a little bug on maps
29 | if c.Funcs == nil {
30 | c.Funcs = make(map[string]interface{}, 0)
31 | }
32 |
33 | return &Engine{Config: c}
34 | }
35 |
36 | // Funcs should returns the helper funcs
37 | func (e *Engine) Funcs() map[string]interface{} {
38 | return e.Config.Funcs
39 | }
40 |
41 | // LoadDirectory builds the amber templates
42 | func (e *Engine) LoadDirectory(directory string, extension string) error {
43 | opt := amber.DirOptions{}
44 | opt.Recursive = true
45 |
46 | // prepare the global amber funcs
47 | funcs := template.FuncMap{}
48 |
49 | for k, v := range amber.FuncMap { // add the amber's default funcs
50 | funcs[k] = v
51 | }
52 |
53 | if e.Config.Funcs != nil { // add the config's funcs
54 | for k, v := range e.Config.Funcs {
55 | funcs[k] = v
56 | }
57 | }
58 |
59 | amber.FuncMap = funcs //set the funcs
60 | opt.Ext = extension
61 |
62 | templates, err := amber.CompileDir(directory, opt, amber.DefaultOptions) // this returns the map with stripped extension, we want extension so we copy the map
63 | if err == nil {
64 | e.mu.Lock()
65 | defer e.mu.Unlock()
66 | e.templateCache = make(map[string]*template.Template)
67 | for k, v := range templates {
68 | name := filepath.ToSlash(k + opt.Ext)
69 | e.templateCache[name] = v
70 | delete(templates, k)
71 | }
72 |
73 | }
74 | return err
75 | }
76 |
77 | // LoadAssets builds the templates from binary assets
78 | func (e *Engine) LoadAssets(virtualDirectory string, virtualExtension string, assetFn func(name string) ([]byte, error), namesFn func() []string) error {
79 | e.templateCache = make(map[string]*template.Template)
80 | // prepare the global amber funcs
81 | funcs := template.FuncMap{}
82 |
83 | for k, v := range amber.FuncMap { // add the amber's default funcs
84 | funcs[k] = v
85 | }
86 |
87 | if e.Config.Funcs != nil { // add the config's funcs
88 | for k, v := range e.Config.Funcs {
89 | funcs[k] = v
90 | }
91 | }
92 | if len(virtualDirectory) > 0 {
93 | if virtualDirectory[0] == '.' { // first check for .wrong
94 | virtualDirectory = virtualDirectory[1:]
95 | }
96 | if virtualDirectory[0] == '/' || virtualDirectory[0] == filepath.Separator { // second check for /something, (or ./something if we had dot on 0 it will be removed
97 | virtualDirectory = virtualDirectory[1:]
98 | }
99 | }
100 | amber.FuncMap = funcs //set the funcs
101 |
102 | e.mu.Lock()
103 | defer e.mu.Unlock()
104 |
105 | names := namesFn()
106 |
107 | for _, path := range names {
108 | if !strings.HasPrefix(path, virtualDirectory) {
109 | continue
110 | }
111 | ext := filepath.Ext(path)
112 | if ext == virtualExtension {
113 |
114 | rel, err := filepath.Rel(virtualDirectory, path)
115 | if err != nil {
116 | return err
117 | }
118 |
119 | buf, err := assetFn(path)
120 | if err != nil {
121 | return err
122 | }
123 |
124 | name := filepath.ToSlash(rel)
125 | tmpl, err := amber.CompileData(buf, name, amber.DefaultOptions)
126 |
127 | if err != nil {
128 | return err
129 | }
130 |
131 | e.templateCache[name] = tmpl
132 | }
133 | }
134 |
135 | return nil
136 | }
137 |
138 | func (e *Engine) fromCache(relativeName string) *template.Template {
139 | e.mu.Lock()
140 | tmpl, ok := e.templateCache[relativeName]
141 | if ok {
142 | e.mu.Unlock()
143 | return tmpl
144 | }
145 | e.mu.Unlock()
146 | return nil
147 | }
148 |
149 | // ExecuteWriter executes a templates and write its results to the out writer
150 | func (e *Engine) ExecuteWriter(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) error {
151 | if tmpl := e.fromCache(name); tmpl != nil {
152 | return tmpl.ExecuteTemplate(out, name, binding)
153 | }
154 |
155 | return fmt.Errorf("[IRIS TEMPLATES] Template with name %s doesn't exists in the dir", name)
156 | }
157 |
158 | // ExecuteRaw receives, parse and executes raw source template contents
159 | // it's super-simple function without options and funcs, it's not used widely
160 | // implements the EngineRawExecutor interface
161 | func (e *Engine) ExecuteRaw(src string, wr io.Writer, binding interface{}) (err error) {
162 | tmpl, err := amber.Compile(src, amber.DefaultOptions)
163 | if err != nil {
164 | return err
165 | }
166 | return tmpl.Execute(wr, binding)
167 | }
168 |
--------------------------------------------------------------------------------
/amber/config.go:
--------------------------------------------------------------------------------
1 | package amber
2 |
3 | // Config contains fields useful to configure this template engine
4 | type Config struct {
5 | // Funcs for the html/template result, amber default funcs are not overrided so use it without worries
6 | Funcs map[string]interface{}
7 | }
8 |
9 | // DefaultConfig returns the default configuration
10 | func DefaultConfig() Config {
11 | return Config{Funcs: make(map[string]interface{})}
12 | }
13 |
--------------------------------------------------------------------------------
/django/README.md:
--------------------------------------------------------------------------------
1 | ## Folder information
2 |
3 | This folder contains the buit'n [django/pongo2](https://github.com/flosch/pongo2) cross-framework template engine support.
4 |
--------------------------------------------------------------------------------
/django/config.go:
--------------------------------------------------------------------------------
1 | package django
2 |
3 | import "github.com/flosch/pongo2"
4 |
5 | type (
6 | // Value conversion for pongo2.Value
7 | Value pongo2.Value
8 | // Error conversion for pongo2.Error
9 | Error pongo2.Error
10 | // FilterFunction conversion for pongo2.FilterFunction
11 | FilterFunction func(in *Value, param *Value) (out *Value, err *Error)
12 | )
13 |
14 | // Config for django template engine
15 | type Config struct {
16 | // Filters for pongo2, map[name of the filter] the filter function . The filters are auto register
17 | Filters map[string]FilterFunction
18 | // Globals share context fields between templates. https://github.com/flosch/pongo2/issues/35
19 | Globals map[string]interface{}
20 | // DebugTemplates enables template debugging.
21 | // The verbose error messages will appear in browser instead of quiet passes with error code
22 | DebugTemplates bool
23 | }
24 |
25 | // DefaultConfig returns the default configuration for the django template engine
26 | func DefaultConfig() Config {
27 | return Config{
28 | Filters: make(map[string]FilterFunction),
29 | Globals: make(map[string]interface{}, 0),
30 | DebugTemplates: false,
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/engine.go:
--------------------------------------------------------------------------------
1 | package template
2 |
3 | import (
4 | "io"
5 | )
6 |
7 | type (
8 | // Engine the interface that all template engines must implement
9 | Engine interface {
10 | // LoadDirectory builds the templates, usually by directory and extension but these are engine's decisions
11 | LoadDirectory(directory string, extension string) error
12 | // LoadAssets loads the templates by binary
13 | // assetFn is a func which returns bytes, use it to load the templates by binary
14 | // namesFn returns the template filenames
15 | LoadAssets(virtualDirectory string, virtualExtension string, assetFn func(name string) ([]byte, error), namesFn func() []string) error
16 |
17 | // ExecuteWriter finds, execute a template and write its result to the out writer
18 | // options are the optional runtime options can be passed by user and catched by the template engine when render
19 | // an example of this is the "layout" or "gzip" option
20 | ExecuteWriter(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) error
21 | }
22 |
23 | // EngineFuncs is optional interface for the Engine
24 | // used to insert the helper funcs
25 | EngineFuncs interface {
26 | // Funcs should returns the context or the funcs,
27 | // this property is used in order to register any optional helper funcs
28 | Funcs() map[string]interface{}
29 | }
30 |
31 | // EngineRawExecutor is optional interface for the Engine
32 | // used to receive and parse a raw template string instead of a filename
33 | EngineRawExecutor interface {
34 | // ExecuteRaw is super-simple function without options and funcs, it's not used widely
35 | ExecuteRaw(src string, wr io.Writer, binding interface{}) error
36 | }
37 | )
38 |
39 | // Below are just helpers for my two web frameworks which you can use also to your web app
40 |
41 | // NoLayout to disable layout for a particular template file
42 | const NoLayout = "@.|.@no_layout@.|.@" // html/html.go. handlebars/handlebars.go. It's the same but the var is separated care for the future here.
43 |
44 | // GetGzipOption receives a default value and the render options map and returns if gzip is enabled for this render action
45 | func GetGzipOption(defaultValue bool, options map[string]interface{}) bool {
46 | gzipOpt := options["gzip"] // we only need that, so don't create new map to keep the options.
47 | if b, isBool := gzipOpt.(bool); isBool {
48 | return b
49 | }
50 | return defaultValue
51 | }
52 |
53 | // GetCharsetOption receives a default value and the render options map and returns the correct charset for this render action
54 | func GetCharsetOption(defaultValue string, options map[string]interface{}) string {
55 | charsetOpt := options["charset"]
56 | if s, isString := charsetOpt.(string); isString {
57 | return s
58 | }
59 | return defaultValue
60 | }
61 |
--------------------------------------------------------------------------------
/handlebars/README.md:
--------------------------------------------------------------------------------
1 | ## Folder information
2 |
3 | This folder contains the buit'n [handlebars/raymond](https://github.com/aymerick/raymond) cross-framework template engine support.
4 |
--------------------------------------------------------------------------------
/handlebars/config.go:
--------------------------------------------------------------------------------
1 | package handlebars
2 |
3 | // Config for handlebars template engine
4 | type Config struct {
5 | // Helpers for Handlebars, you can register your own by raymond.RegisterHelper(name string, a interface{}) or RegisterHelpers(map[string]interface{})
6 | // or just fill this method, do not override it it is not nil by default (because of Iris' helpers (url and urlpath)
7 | Helpers map[string]interface{}
8 | Layout string
9 | }
10 |
11 | // DefaultConfig returns the default configs for the handlebars template engine
12 | func DefaultConfig() Config {
13 | return Config{
14 | Helpers: make(map[string]interface{}, 0),
15 | Layout: "",
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/html/README.md:
--------------------------------------------------------------------------------
1 | ## Folder information
2 |
3 | This folder contains the buit'n and the default [html/template](https://golang.org/pkg/text/template) cross-framework template engine support.
4 |
--------------------------------------------------------------------------------
/html/config.go:
--------------------------------------------------------------------------------
1 | package html
2 |
3 | // Config for html template engine
4 | type Config struct {
5 | Left string
6 | Right string
7 | Layout string
8 | Funcs map[string]interface{}
9 | LayoutFuncs map[string]interface{}
10 | }
11 |
12 | // DefaultConfig returns the default configs for the html template engine
13 | func DefaultConfig() Config {
14 | return Config{
15 | Left: "{{",
16 | Right: "}}",
17 | Layout: "",
18 | Funcs: make(map[string]interface{}, 0),
19 | LayoutFuncs: make(map[string]interface{}, 0),
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/loader.go:
--------------------------------------------------------------------------------
1 | package template
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 |
7 | "github.com/kataras/go-errors"
8 | )
9 |
10 | var (
11 | // DefaultExtension the default file extension if empty setted
12 | DefaultExtension = ".html"
13 | // DefaultDirectory the default directory if empty setted
14 | DefaultDirectory = "." + string(os.PathSeparator) + "templates"
15 | )
16 |
17 | type (
18 | // Loader contains the funcs to set the location for the templates by directory or by binary
19 | Loader struct {
20 | Dir string
21 | Extension string
22 | // AssetFn and NamesFn used when files are distributed inside the app executable
23 | AssetFn func(name string) ([]byte, error)
24 | NamesFn func() []string
25 | }
26 | // BinaryLoader optionally, called after EngineLocation's Directory, used when files are distributed inside the app executable
27 | // sets the AssetFn and NamesFn
28 | BinaryLoader struct {
29 | *Loader
30 | }
31 | )
32 |
33 | // NewLoader returns a default Loader which is used to load template engine(s)
34 | func NewLoader() *Loader {
35 | return &Loader{Dir: DefaultDirectory, Extension: DefaultExtension}
36 | }
37 |
38 | // Directory sets the directory to load from
39 | // returns the Binary location which is optional
40 | func (t *Loader) Directory(dir string, fileExtension string) *BinaryLoader {
41 | if dir == "" {
42 | dir = DefaultDirectory // the default templates dir
43 | }
44 | if fileExtension == "" {
45 | fileExtension = DefaultExtension
46 | } else if fileExtension[0] != '.' { // if missing the start dot
47 | fileExtension = "." + fileExtension
48 | }
49 |
50 | t.Dir = dir
51 | t.Extension = fileExtension
52 |
53 | return &BinaryLoader{Loader: t}
54 | }
55 |
56 | // Binary optionally, called after Loader.Directory, used when files are distributed inside the app executable
57 | // sets the AssetFn and NamesFn
58 | func (t *BinaryLoader) Binary(assetFn func(name string) ([]byte, error), namesFn func() []string) {
59 | if assetFn == nil || namesFn == nil {
60 | return
61 | }
62 |
63 | t.AssetFn = assetFn
64 | t.NamesFn = namesFn
65 | // if extension is not static(setted by .Directory)
66 | if t.Extension == "" {
67 | if names := namesFn(); len(names) > 0 {
68 | t.Extension = filepath.Ext(names[0]) // we need the extension to get the correct template engine on the Render method
69 | }
70 | }
71 | }
72 |
73 | // IsBinary returns true if .Binary is called and AssetFn and NamesFn are setted
74 | func (t *Loader) IsBinary() bool {
75 | return t.AssetFn != nil && t.NamesFn != nil
76 | }
77 |
78 | var errMissingDirectoryOrAssets = errors.New("missing Directory or Assets by binary for the template engine")
79 |
80 | // LoadEngine receives a template Engine and calls its LoadAssets or the LoadDirectory with the loader's locations
81 | func (t *Loader) LoadEngine(e Engine) error {
82 | if t.Dir == "" {
83 | return errMissingDirectoryOrAssets
84 | }
85 |
86 | if t.IsBinary() {
87 | // don't try to put abs path here
88 | // fixes: http://support.iris-go.com/d/22-template-binary-problem-in-v6
89 | return e.LoadAssets(t.Dir, t.Extension, t.AssetFn, t.NamesFn)
90 | }
91 |
92 | // fixes when user tries to execute the binary from a temp location while the templates are relatively located
93 | absDir, err := filepath.Abs(t.Dir)
94 | // panic here of course.
95 | if err != nil {
96 | panic("couldn't find the dir in the relative dir: '" + t.Dir +
97 | "' neither as absolute: '" + absDir + "'\n" + err.Error())
98 | }
99 | return e.LoadDirectory(absDir, t.Extension)
100 | }
101 |
--------------------------------------------------------------------------------
/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kataras/go-template/a4a986b413e8d88ebd894b4a3e327314069f2439/logo.jpg
--------------------------------------------------------------------------------
/markdown/README.md:
--------------------------------------------------------------------------------
1 | ## Folder information
2 |
3 | This folder contains the [markdown/blackfriday](https://github.com/russross/blackfriday) cross-framework template engine support.
4 |
--------------------------------------------------------------------------------
/markdown/config.go:
--------------------------------------------------------------------------------
1 | package markdown
2 |
3 | // Config for markdown template engine
4 | type Config struct {
5 | // Sanitize if true then returns safe html, default is false
6 | Sanitize bool
7 | }
8 |
9 | // DefaultConfig returns the default configs for the markdown template engine
10 | func DefaultConfig() Config {
11 | return Config{
12 | Sanitize: false,
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/markdown/markdown.go:
--------------------------------------------------------------------------------
1 | package markdown
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "io/ioutil"
7 | "os"
8 | "path/filepath"
9 | "strings"
10 | "sync"
11 |
12 | "github.com/microcosm-cc/bluemonday"
13 | "github.com/russross/blackfriday"
14 | )
15 |
16 | // Supports RAW markdown only, no context binding or layout, to use dynamic markdown with other template engine use the context.Markdown/MarkdownString
17 |
18 | type (
19 | // Engine the jade engine
20 | Engine struct {
21 | Config Config
22 | templateCache map[string][]byte
23 | mu sync.Mutex
24 | }
25 | )
26 |
27 | // New creates and returns a Pongo template engine
28 | func New(cfg ...Config) *Engine {
29 | c := DefaultConfig()
30 | if len(cfg) > 0 {
31 | c = cfg[0]
32 | }
33 |
34 | return &Engine{Config: c, templateCache: make(map[string][]byte)}
35 | }
36 |
37 | // LoadDirectory builds the markdown templates
38 | func (e *Engine) LoadDirectory(dir string, extension string) error {
39 | e.mu.Lock()
40 | defer e.mu.Unlock()
41 | var templateErr error
42 | // Walk the supplied directory and compile any files that match our extension list.
43 | filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
44 |
45 | if info == nil || info.IsDir() {
46 |
47 | } else {
48 |
49 | rel, err := filepath.Rel(dir, path)
50 | if err != nil {
51 | templateErr = err
52 | return err
53 | }
54 |
55 | ext := filepath.Ext(rel)
56 |
57 | if ext == extension {
58 | buf, err := ioutil.ReadFile(path)
59 | if err != nil {
60 | templateErr = err
61 | return err
62 | }
63 |
64 | buf = blackfriday.MarkdownCommon(buf)
65 | if e.Config.Sanitize {
66 | buf = bluemonday.UGCPolicy().SanitizeBytes(buf)
67 | }
68 |
69 | if err != nil {
70 | templateErr = err
71 | return err
72 | }
73 | name := filepath.ToSlash(rel)
74 | e.templateCache[name] = buf
75 |
76 | }
77 | }
78 | return nil
79 | })
80 |
81 | return templateErr
82 |
83 | }
84 |
85 | // LoadAssets loads the templates by binary
86 | func (e *Engine) LoadAssets(virtualDirectory string, virtualExtension string, assetFn func(name string) ([]byte, error), namesFn func() []string) error {
87 | if len(virtualDirectory) > 0 {
88 | if virtualDirectory[0] == '.' { // first check for .wrong
89 | virtualDirectory = virtualDirectory[1:]
90 | }
91 | if virtualDirectory[0] == '/' || virtualDirectory[0] == os.PathSeparator { // second check for /something, (or ./something if we had dot on 0 it will be removed
92 | virtualDirectory = virtualDirectory[1:]
93 | }
94 | }
95 |
96 | e.mu.Lock()
97 | defer e.mu.Unlock()
98 |
99 | names := namesFn()
100 | for _, path := range names {
101 | if !strings.HasPrefix(path, virtualDirectory) {
102 | continue
103 | }
104 |
105 | rel, err := filepath.Rel(virtualDirectory, path)
106 | if err != nil {
107 | return err
108 | }
109 |
110 | ext := filepath.Ext(rel)
111 | if ext == virtualExtension {
112 |
113 | buf, err := assetFn(path)
114 | if err != nil {
115 | return err
116 | }
117 | b := blackfriday.MarkdownCommon(buf)
118 | if e.Config.Sanitize {
119 | b = bluemonday.UGCPolicy().SanitizeBytes(b)
120 | }
121 | name := filepath.ToSlash(rel)
122 | e.templateCache[name] = b
123 |
124 | }
125 |
126 | }
127 | return nil
128 | }
129 |
130 | func (e *Engine) fromCache(relativeName string) []byte {
131 | e.mu.Lock()
132 |
133 | tmpl, ok := e.templateCache[relativeName]
134 |
135 | if ok {
136 | e.mu.Unlock() // defer is slow
137 | return tmpl
138 | }
139 | e.mu.Unlock() // defer is slow
140 | return nil
141 | }
142 |
143 | // ExecuteWriter executes a templates and write its results to the out writer
144 | // layout here is useless
145 | func (e *Engine) ExecuteWriter(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) error {
146 | if tmpl := e.fromCache(name); tmpl != nil {
147 | _, err := out.Write(tmpl)
148 | return err
149 | }
150 |
151 | return fmt.Errorf("[IRIS TEMPLATES] Template with name %s doesn't exists in the dir", name)
152 | }
153 |
154 | // ExecuteRaw receives, parse and executes raw source template contents
155 | // it's super-simple function without options and funcs, it's not used widely
156 | // implements the EngineRawExecutor interface
157 | func (e *Engine) ExecuteRaw(src string, wr io.Writer, binding interface{}) (err error) {
158 | parsed := blackfriday.MarkdownCommon([]byte(src))
159 | if e.Config.Sanitize {
160 | parsed = bluemonday.UGCPolicy().SanitizeBytes(parsed)
161 | }
162 | _, err = wr.Write(parsed)
163 | return
164 | }
165 |
--------------------------------------------------------------------------------
/pug/README.md:
--------------------------------------------------------------------------------
1 | ## Folder information
2 |
3 | This folder contains the [pug/jade](https://github.com/Joker/jade) cross-framework template engine support.
4 |
--------------------------------------------------------------------------------
/pug/config.go:
--------------------------------------------------------------------------------
1 | package pug
2 |
3 | import "github.com/kataras/go-template/html"
4 |
5 | // Pug is the 'jade', same configs as the html engine
6 |
7 | // Config for pug template engine
8 | type Config html.Config
9 |
10 | // DefaultConfig returns the default configuration for the pug(jade) template engine
11 | func DefaultConfig() Config {
12 | return Config(html.DefaultConfig())
13 | }
14 |
--------------------------------------------------------------------------------
/pug/pug.go:
--------------------------------------------------------------------------------
1 | //Package pug the JadeEngine's functionality lives inside ../html now
2 | package pug
3 |
4 | import (
5 | "github.com/Joker/jade"
6 | "github.com/kataras/go-template/html"
7 | )
8 |
9 | // New creates and returns the Pug template engine
10 | func New(cfg ...Config) *html.Engine {
11 | c := DefaultConfig()
12 | if len(cfg) > 0 {
13 | c = cfg[0]
14 | }
15 | // pass the Pug/Jade configs to the html's configuration
16 |
17 | s := html.New(html.Config(c))
18 | s.Middleware = jade.Parse
19 | return s
20 | }
21 |
--------------------------------------------------------------------------------
/template.go:
--------------------------------------------------------------------------------
1 | // Package template provides the easier way to use templates via template engine
2 | // supports multiple template engines with different file extensions
3 | // 6 template engines supported:
4 | // standard html/template
5 | // amber
6 | // django
7 | // handlebars
8 | // pug(jade)
9 | // markdown
10 | package template
11 |
12 | const (
13 | // Version current version number
14 | Version = "0.0.5"
15 | )
16 |
--------------------------------------------------------------------------------
/vendor/github.com/Joker/jade/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015, Joker
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of jade nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/vendor/github.com/Joker/jade/config.go:
--------------------------------------------------------------------------------
1 | package jade
2 |
3 | var (
4 | // Pretty print if true
5 | PrettyOutput = true
6 |
7 | // Output indent strring for pretty print
8 | OutputIndent = " "
9 |
10 | // Tabulation size of parse file
11 | TabSize = 4
12 |
13 | // Left go-template delim
14 | LeftDelim = "{{"
15 |
16 | // Right go-template delim
17 | RightDelim = "}}"
18 | )
19 |
20 | const (
21 | nestIndent = true
22 | lineIndent = false
23 |
24 | tabComment = "//-"
25 | htmlComment = "//"
26 |
27 | interDelim = "#{"
28 | unEscInterDelim = "!{"
29 | rightInterDelim = "}"
30 | )
31 |
32 | var itemToStr = map[itemType]string{
33 | itemError: "itemError",
34 | itemEOF: "itemEOF",
35 | itemEndL: "itemEndL",
36 | itemEndAttr: "itemEndAttr",
37 | itemIdentSpace: "itemIdentSpace",
38 | itemIdentTab: "itemIdentTab",
39 | itemTag: "itemTag",
40 | itemVoidTag: "itemVoidTag",
41 | itemInlineTag: "itemInlineTag",
42 | itemInlineVoidTag: "itemInlineVoidTag",
43 | itemHTMLTag: "itemHTMLTag",
44 | itemDiv: "itemDiv",
45 | itemID: "itemID",
46 | itemClass: "itemClass",
47 | itemAttr: "itemAttr",
48 | itemAttrN: "itemAttrN",
49 | itemAttrName: "itemAttrName",
50 | itemAttrVoid: "itemAttrVoid",
51 | itemAction: "itemAction",
52 | itemInlineAction: "itemInlineAction",
53 | itemInlineText: "itemInlineText",
54 | itemFilter: "itemFilter",
55 | itemDoctype: "itemDoctype",
56 | itemComment: "itemComment",
57 | itemBlank: "itemBlank",
58 | itemParentIdent: "itemParentIdent",
59 | itemChildIdent: "itemChildIdent",
60 | itemText: "itemText",
61 | }
62 |
63 | var key = map[string]itemType{
64 | "area": itemVoidTag,
65 | "base": itemVoidTag,
66 | "col": itemVoidTag,
67 | "command": itemVoidTag,
68 | "embed": itemVoidTag,
69 | "hr": itemVoidTag,
70 | "input": itemVoidTag,
71 | "keygen": itemVoidTag,
72 | "link": itemVoidTag,
73 | "meta": itemVoidTag,
74 | "param": itemVoidTag,
75 | "source": itemVoidTag,
76 | "track": itemVoidTag,
77 | "wbr": itemVoidTag,
78 |
79 | "template": itemAction,
80 | "end": itemAction,
81 | "include": itemAction,
82 | "extends": itemAction,
83 |
84 | "if": itemActionEnd,
85 | "else": itemActionEnd,
86 | "range": itemActionEnd,
87 | "with": itemActionEnd,
88 | "block": itemActionEnd,
89 | "define": itemActionEnd,
90 | "each": itemActionEnd,
91 | "for": itemActionEnd,
92 | "while": itemActionEnd,
93 | "unless": itemActionEnd,
94 | "case": itemActionEnd,
95 |
96 | // "if": itemIf,
97 | // "else": itemElse,
98 | // "end": itemEnd,
99 | // "range": itemRange,
100 | // "with": itemWith,
101 | // "nil": itemNil,
102 | // "template": itemTemplate,
103 | // "define": itemDefine,
104 | "mixin": itemDefine,
105 |
106 | "a": itemInlineTag,
107 | "abbr": itemInlineTag,
108 | "acronym": itemInlineTag,
109 | "b": itemInlineTag,
110 | "code": itemInlineTag,
111 | "em": itemInlineTag,
112 | "font": itemInlineTag,
113 | "i": itemInlineTag,
114 | "ins": itemInlineTag,
115 | "kbd": itemInlineTag,
116 | "map": itemInlineTag,
117 | "samp": itemInlineTag,
118 | "small": itemInlineTag,
119 | "span": itemInlineTag,
120 | "strong": itemInlineTag,
121 | "sub": itemInlineTag,
122 | "sup": itemInlineTag,
123 |
124 | "br": itemInlineVoidTag,
125 | "img": itemInlineVoidTag,
126 | }
127 |
--------------------------------------------------------------------------------
/vendor/github.com/Joker/jade/jade_parse.go:
--------------------------------------------------------------------------------
1 | package jade
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | func (t *tree) parse(treeSet map[string]*tree) (next node) {
8 | token := t.next()
9 | t.Root = t.newList(token.pos)
10 |
11 | for token.typ != itemEOF {
12 |
13 | switch token.typ {
14 | case itemError:
15 | t.errorf("%s", token.val)
16 | case itemDoctype:
17 | t.Root.append(t.newDoctype(token.pos, token.val))
18 | case itemHTMLTag:
19 | t.Root.append(t.newLine(token.pos, token.val, token.typ, 0, 0))
20 |
21 | case itemTag, itemDiv, itemInlineTag, itemAction, itemActionEnd, itemDefine, itemComment:
22 | nest := t.newNest(token.pos, token.val, token.typ, 0, 0)
23 | if token.typ < itemComment {
24 | t.parseAttr(nest)
25 | }
26 | t.Root.append(nest)
27 | t.parseInside(nest)
28 |
29 | case itemBlank:
30 | nest := t.newNest(token.pos, token.val, token.typ, 0, 0)
31 | t.parseInside(nest)
32 | }
33 |
34 | token = t.next()
35 |
36 | }
37 | return nil
38 | }
39 |
40 | func (t *tree) parseInside(outTag *nestNode) int {
41 | indentCount := 0
42 | token := t.next()
43 |
44 | for token.typ != itemEOF {
45 | switch token.typ {
46 | case itemError:
47 | t.errorf("%s", token.val)
48 |
49 | case itemEndL:
50 | indentCount = 0
51 | case itemIdentSpace:
52 | indentCount++
53 | case itemIdentTab:
54 | indentCount += TabSize
55 | case itemParentIdent:
56 | indentCount = outTag.Indent + 1 // for "tag: tag: tag"
57 | case itemChildIdent:
58 | return indentCount // for "]"
59 |
60 | case itemDoctype:
61 | t.backup()
62 | return indentCount
63 | case itemInlineText, itemInlineAction:
64 | outTag.append(t.newLine(token.pos, token.val, token.typ, indentCount, outTag.Nesting+1))
65 |
66 | case itemHTMLTag, itemText:
67 | if indentCount > outTag.Indent {
68 | outTag.append(t.newLine(token.pos, token.val, token.typ, indentCount, outTag.Nesting+1))
69 | } else {
70 | t.backup()
71 | return indentCount
72 | }
73 |
74 | case itemVoidTag, itemInlineVoidTag:
75 | if indentCount > outTag.Indent {
76 | nest := t.newNest(token.pos, token.val, token.typ, indentCount, outTag.Nesting+1)
77 | t.parseAttr(nest)
78 | outTag.append(nest)
79 | } else {
80 | t.backup()
81 | return indentCount
82 | }
83 |
84 | case itemTag, itemDiv, itemInlineTag:
85 | if indentCount > outTag.Indent {
86 | nest := t.newNest(token.pos, token.val, token.typ, indentCount, outTag.Nesting+1)
87 | if t.parseAttr(nest) {
88 | outTag.append(nest)
89 | indentCount = t.parseInside(nest)
90 | } else {
91 | nest.typ = itemVoidTag
92 | outTag.append(nest)
93 | }
94 | } else {
95 | t.backup()
96 | return indentCount
97 | }
98 |
99 | case itemAction, itemActionEnd, itemTemplate, itemDefine:
100 | if indentCount > outTag.Indent {
101 | nest := t.newNest(token.pos, token.val, token.typ, indentCount, outTag.Nesting+1)
102 | outTag.append(nest)
103 | indentCount = t.parseInside(nest)
104 | if strings.HasPrefix(nest.Tag, "if") || strings.HasPrefix(nest.Tag, "with") {
105 | action := t.next()
106 | if strings.HasPrefix(action.val, "else") {
107 | nest.typ = itemAction
108 | }
109 | t.backup()
110 | }
111 | } else {
112 | t.backup()
113 | return indentCount
114 | }
115 |
116 | case itemBlank, itemComment:
117 | if indentCount > outTag.Indent {
118 | nest := t.newNest(token.pos, token.val, token.typ, indentCount, outTag.Nesting+1)
119 | if token.typ == itemComment {
120 | outTag.append(nest)
121 | }
122 | indentCount = t.parseInside(nest)
123 | } else {
124 | t.backup()
125 | return indentCount
126 | }
127 |
128 | }
129 | token = t.next()
130 | }
131 | t.backup()
132 | return indentCount
133 | }
134 |
135 | func (t *tree) parseAttr(currentTag *nestNode) bool {
136 | for {
137 | attr := t.next()
138 | switch attr.typ {
139 | case itemError:
140 | t.errorf("%s", attr.val)
141 | case itemID:
142 | if len(currentTag.id) > 0 {
143 | t.errorf("unexpected second id \"%s\" ", attr.val)
144 | }
145 | currentTag.id = attr.val
146 | case itemClass:
147 | currentTag.class = append(currentTag.class, attr.val)
148 | case itemAttr, itemAttrN, itemAttrName, itemAttrVoid:
149 | currentTag.append(t.newAttr(attr.pos, attr.val, attr.typ))
150 | case itemEndTag:
151 | currentTag.append(t.newAttr(attr.pos, "/>", itemEndTag))
152 | return false
153 | default:
154 | t.backup()
155 | currentTag.append(t.newAttr(attr.pos, ">", itemEndAttr))
156 | return true
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/vendor/github.com/Joker/jade/lex.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package jade
6 |
7 | import (
8 | "fmt"
9 | "strings"
10 | "unicode"
11 | "unicode/utf8"
12 | )
13 |
14 | // item represents a token or text string returned from the scanner.
15 | type item struct {
16 | typ itemType // The type of this item.
17 | pos psn // The starting position, in bytes, of this item in the input string.
18 | val string // The value of this item.
19 | }
20 |
21 | func (i item) String() string {
22 | switch {
23 | case i.typ == itemEOF:
24 | return "EOF"
25 | case i.typ == itemError:
26 | return i.val
27 | case len(i.val) > 10:
28 | return fmt.Sprintf("%.10q...", i.val)
29 | }
30 | return fmt.Sprintf("%q", i.val)
31 | }
32 |
33 | const eof = -1
34 |
35 | // stateFn represents the state of the scanner as a function that returns the next state.
36 | type stateFn func(*lexer) stateFn
37 |
38 | // lexer holds the state of the scanner.
39 | type lexer struct {
40 | name string // the name of the input; used only for error reports
41 | input string // the string being scanned
42 | leftDelim string // start of action
43 | rightDelim string // end of action
44 | state stateFn // the next lexing function to enter
45 | pos psn // current position in the input
46 | start psn // start position of this item
47 | width psn // width of last rune read from input
48 | lastPos psn // position of most recent item returned by nextItem
49 | items chan item // channel of scanned items
50 | previous int // previous depth
51 | parenDepth int // nesting depth
52 | env map[mode]int
53 | }
54 |
55 | // next returns the next rune in the input.
56 | func (l *lexer) next() rune {
57 | if int(l.pos) >= len(l.input) {
58 | l.width = 0
59 | return eof
60 | }
61 | r, w := utf8.DecodeRuneInString(l.input[l.pos:])
62 | l.width = psn(w)
63 | l.pos += l.width
64 | return r
65 | }
66 |
67 | // peek returns but does not consume the next rune in the input.
68 | func (l *lexer) peek() rune {
69 | r := l.next()
70 | l.backup()
71 | return r
72 | }
73 |
74 | // backup steps back one rune. Can only be called once per call of next.
75 | func (l *lexer) backup() {
76 | l.pos -= l.width
77 | }
78 |
79 | // emit passes an item back to the client.
80 | func (l *lexer) emit(t itemType) {
81 | l.items <- item{t, l.start, l.input[l.start:l.pos]}
82 | l.start = l.pos
83 | }
84 |
85 | // ignore skips over the pending input before this point.
86 | func (l *lexer) ignore() {
87 | l.start = l.pos
88 | }
89 |
90 | // accept consumes the next rune if it's from the valid set.
91 | func (l *lexer) accept(valid string) bool {
92 | if strings.IndexRune(valid, l.next()) >= 0 {
93 | return true
94 | }
95 | l.backup()
96 | return false
97 | }
98 |
99 | // acceptRun consumes a run of runes from the valid set.
100 | func (l *lexer) acceptRun(valid string) {
101 | for strings.IndexRune(valid, l.next()) >= 0 {
102 | }
103 | l.backup()
104 | }
105 |
106 | // lineNumber reports which line we're on, based on the position of
107 | // the previous item returned by nextItem. Doing it this way
108 | // means we don't have to worry about peek double counting.
109 | func (l *lexer) lineNumber() int {
110 | return 1 + strings.Count(l.input[:l.lastPos], "\n")
111 | }
112 |
113 | // errorf returns an error token and terminates the scan by passing
114 | // back a nil pointer that will be the next state, terminating l.nextItem.
115 | func (l *lexer) errorf(format string, args ...interface{}) stateFn {
116 | l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
117 | return nil
118 | }
119 |
120 | // nextItem returns the next item from the input.
121 | func (l *lexer) nextItem() item {
122 | item := <-l.items
123 | l.lastPos = item.pos
124 | return item
125 | }
126 |
127 | // lex creates a new scanner for the input string.
128 | func lex(name, input, left, right string) *lexer {
129 | if left == "" {
130 | left = LeftDelim
131 | }
132 | if right == "" {
133 | right = RightDelim
134 | }
135 | l := &lexer{
136 | name: name,
137 | input: input,
138 | leftDelim: left,
139 | rightDelim: right,
140 | items: make(chan item),
141 | env: make(map[mode]int),
142 | }
143 | go l.run()
144 | return l
145 | }
146 |
147 | // isSpace reports whether r is a space character.
148 | func isSpace(r rune) bool {
149 | return r == ' ' || r == '\t'
150 | }
151 |
152 | // isEndOfLine reports whether r is an end-of-line character.
153 | func isEndOfLine(r rune) bool {
154 | return r == '\r' || r == '\n'
155 | }
156 |
157 | // isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
158 | func isAlphaNumeric(r rune) bool {
159 | return r == '_' || r == '-' || unicode.IsLetter(r) || unicode.IsDigit(r)
160 | }
161 |
--------------------------------------------------------------------------------
/vendor/github.com/Joker/jade/node.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package jade
6 |
7 | import (
8 | "bytes"
9 | "fmt"
10 | )
11 |
12 | var textFormat = "%s" // Changed to "%q" in tests for better error messages.
13 |
14 | // A Node is an element in the parse tree. The interface is trivial.
15 | // The interface contains an unexported method so that only
16 | // types local to this package can satisfy it.
17 | type node interface {
18 | Type() nodeType
19 | position() psn // byte position of start of node in full original input string
20 | String() string
21 |
22 | // Copy does a deep copy of the Node and all its components.
23 | // To avoid type assertions, some XxxNodes also have specialized
24 | // CopyXxx methods that return *XxxNode.
25 | Copy() node
26 |
27 | // tree returns the containing *Tree.
28 | // It is unexported so all implementations of Node are in this package.
29 | tree() *tree
30 | tp() itemType
31 | }
32 |
33 | // Type returns itself and provides an easy default implementation
34 | // for embedding in a Node. Embedded in all non-trivial Nodes.
35 | func (t nodeType) Type() nodeType {
36 | return t
37 | }
38 |
39 | // Pos represents a byte position in the original input text from which
40 | // this template was parsed.
41 | type psn int
42 |
43 | func (p psn) position() psn {
44 | return p
45 | }
46 |
47 | // listNode holds a sequence of nodes.
48 | type listNode struct {
49 | nodeType
50 | psn
51 | tr *tree
52 | Nodes []node // The element nodes in lexical order.
53 | }
54 |
55 | func (t *tree) newList(pos psn) *listNode {
56 | return &listNode{tr: t, nodeType: nodeList, psn: pos}
57 | }
58 |
59 | func (l *listNode) append(n node) {
60 | l.Nodes = append(l.Nodes, n)
61 | }
62 |
63 | func (l *listNode) tree() *tree {
64 | return l.tr
65 | }
66 | func (l *listNode) tp() itemType {
67 | return 0
68 | }
69 |
70 | func (l *listNode) String() string {
71 | b := new(bytes.Buffer)
72 | for _, n := range l.Nodes {
73 | fmt.Fprint(b, n)
74 | }
75 | return b.String()
76 | }
77 |
78 | func (l *listNode) CopyList() *listNode {
79 | if l == nil {
80 | return l
81 | }
82 | n := l.tr.newList(l.psn)
83 | for _, elem := range l.Nodes {
84 | n.append(elem.Copy())
85 | }
86 | return n
87 | }
88 |
89 | func (l *listNode) Copy() node {
90 | return l.CopyList()
91 | }
92 |
--------------------------------------------------------------------------------
/vendor/github.com/Joker/jade/template.go:
--------------------------------------------------------------------------------
1 | // Jade.go - template engine. Package implements Jade-lang templates for generating Go html/template output.
2 | package jade
3 |
4 | import (
5 | "io/ioutil"
6 | "path/filepath"
7 | )
8 |
9 | /*
10 | Parse parses the template definition string to construct a representation of the template for execution.
11 |
12 | Trivial usage:
13 |
14 | package main
15 |
16 | import (
17 | "fmt"
18 | "github.com/Joker/jade"
19 | )
20 |
21 | func main() {
22 | tpl, err := jade.Parse("tpl_name", "doctype 5: html: body: p Hello world!")
23 | if err != nil {
24 | fmt.Printf("Parse error: %v", err)
25 | return
26 | }
27 |
28 | fmt.Printf( "Output:\n\n%s", tpl )
29 | }
30 |
31 | Output:
32 |
33 |
34 |
35 |
36 |
Hello world!
37 |
38 |
39 | */
40 | func Parse(name, text string) (string, error) {
41 | outTpl, err := newTree(name).Parse(text, LeftDelim, RightDelim, make(map[string]*tree))
42 | if err != nil {
43 | return "", err
44 | }
45 | return outTpl.String(), nil
46 | }
47 |
48 | // ParseFile parse the jade template file in given filename
49 | func ParseFile(filename string) (string, error) {
50 | b, err := ioutil.ReadFile(filename)
51 | if err != nil {
52 | return "", err
53 | }
54 | s := string(b)
55 | name := filepath.Base(filename)
56 |
57 | return Parse(name, s)
58 | }
59 |
60 | func (t *tree) String() string {
61 | return t.Root.String()
62 | }
63 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Aymerick JEHANNE
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/VERSION:
--------------------------------------------------------------------------------
1 | 2.0.1
2 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/data_frame.go:
--------------------------------------------------------------------------------
1 | package raymond
2 |
3 | import "reflect"
4 |
5 | // DataFrame represents a private data frame.
6 | //
7 | // Cf. private variables documentation at: http://handlebarsjs.com/block_helpers.html
8 | type DataFrame struct {
9 | parent *DataFrame
10 | data map[string]interface{}
11 | }
12 |
13 | // NewDataFrame instanciates a new private data frame.
14 | func NewDataFrame() *DataFrame {
15 | return &DataFrame{
16 | data: make(map[string]interface{}),
17 | }
18 | }
19 |
20 | // Copy instanciates a new private data frame with receiver as parent.
21 | func (p *DataFrame) Copy() *DataFrame {
22 | result := NewDataFrame()
23 |
24 | for k, v := range p.data {
25 | result.data[k] = v
26 | }
27 |
28 | result.parent = p
29 |
30 | return result
31 | }
32 |
33 | // newIterDataFrame instanciates a new private data frame with receiver as parent and with iteration data set (@index, @key, @first, @last)
34 | func (p *DataFrame) newIterDataFrame(length int, i int, key interface{}) *DataFrame {
35 | result := p.Copy()
36 |
37 | result.Set("index", i)
38 | result.Set("key", key)
39 | result.Set("first", i == 0)
40 | result.Set("last", i == length-1)
41 |
42 | return result
43 | }
44 |
45 | // Set sets a data value.
46 | func (p *DataFrame) Set(key string, val interface{}) {
47 | p.data[key] = val
48 | }
49 |
50 | // Get gets a data value.
51 | func (p *DataFrame) Get(key string) interface{} {
52 | return p.find([]string{key})
53 | }
54 |
55 | // find gets a deep data value
56 | //
57 | // @todo This is NOT consistent with the way we resolve data in template (cf. `evalDataPathExpression()`) ! FIX THAT !
58 | func (p *DataFrame) find(parts []string) interface{} {
59 | data := p.data
60 |
61 | for i, part := range parts {
62 | val := data[part]
63 | if val == nil {
64 | return nil
65 | }
66 |
67 | if i == len(parts)-1 {
68 | // found
69 | return val
70 | }
71 |
72 | valValue := reflect.ValueOf(val)
73 | if valValue.Kind() != reflect.Map {
74 | // not found
75 | return nil
76 | }
77 |
78 | // continue
79 | data = mapStringInterface(valValue)
80 | }
81 |
82 | // not found
83 | return nil
84 | }
85 |
86 | // mapStringInterface converts any `map` to `map[string]interface{}`
87 | func mapStringInterface(value reflect.Value) map[string]interface{} {
88 | result := make(map[string]interface{})
89 |
90 | for _, key := range value.MapKeys() {
91 | result[strValue(key)] = value.MapIndex(key).Interface()
92 | }
93 |
94 | return result
95 | }
96 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/escape.go:
--------------------------------------------------------------------------------
1 | package raymond
2 |
3 | import (
4 | "bytes"
5 | "strings"
6 | )
7 |
8 | //
9 | // That whole file is borrowed from https://github.com/golang/go/tree/master/src/html/escape.go
10 | //
11 | // With changes:
12 | // ' => '
13 | // " => "
14 | //
15 | // To stay in sync with JS implementation, and make mustache tests pass.
16 | //
17 |
18 | type writer interface {
19 | WriteString(string) (int, error)
20 | }
21 |
22 | const escapedChars = `&'<>"`
23 |
24 | func escape(w writer, s string) error {
25 | i := strings.IndexAny(s, escapedChars)
26 | for i != -1 {
27 | if _, err := w.WriteString(s[:i]); err != nil {
28 | return err
29 | }
30 | var esc string
31 | switch s[i] {
32 | case '&':
33 | esc = "&"
34 | case '\'':
35 | esc = "'"
36 | case '<':
37 | esc = "<"
38 | case '>':
39 | esc = ">"
40 | case '"':
41 | esc = """
42 | default:
43 | panic("unrecognized escape character")
44 | }
45 | s = s[i+1:]
46 | if _, err := w.WriteString(esc); err != nil {
47 | return err
48 | }
49 | i = strings.IndexAny(s, escapedChars)
50 | }
51 | _, err := w.WriteString(s)
52 | return err
53 | }
54 |
55 | // Escape escapes special HTML characters.
56 | //
57 | // It can be used by helpers that return a SafeString and that need to escape some content by themselves.
58 | func Escape(s string) string {
59 | if strings.IndexAny(s, escapedChars) == -1 {
60 | return s
61 | }
62 | var buf bytes.Buffer
63 | escape(&buf, s)
64 | return buf.String()
65 | }
66 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/handlebars/doc.go:
--------------------------------------------------------------------------------
1 | // Package handlebars contains all the tests that come from handlebars.js project.
2 | package handlebars
3 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/lexer/token.go:
--------------------------------------------------------------------------------
1 | package lexer
2 |
3 | import "fmt"
4 |
5 | const (
6 | // TokenError represents an error
7 | TokenError TokenKind = iota
8 |
9 | // TokenEOF represents an End Of File
10 | TokenEOF
11 |
12 | //
13 | // Mustache delimiters
14 | //
15 |
16 | // TokenOpen is the OPEN token
17 | TokenOpen
18 |
19 | // TokenClose is the CLOSE token
20 | TokenClose
21 |
22 | // TokenOpenRawBlock is the OPEN_RAW_BLOCK token
23 | TokenOpenRawBlock
24 |
25 | // TokenCloseRawBlock is the CLOSE_RAW_BLOCK token
26 | TokenCloseRawBlock
27 |
28 | // TokenOpenEndRawBlock is the END_RAW_BLOCK token
29 | TokenOpenEndRawBlock
30 |
31 | // TokenOpenUnescaped is the OPEN_UNESCAPED token
32 | TokenOpenUnescaped
33 |
34 | // TokenCloseUnescaped is the CLOSE_UNESCAPED token
35 | TokenCloseUnescaped
36 |
37 | // TokenOpenBlock is the OPEN_BLOCK token
38 | TokenOpenBlock
39 |
40 | // TokenOpenEndBlock is the OPEN_ENDBLOCK token
41 | TokenOpenEndBlock
42 |
43 | // TokenInverse is the INVERSE token
44 | TokenInverse
45 |
46 | // TokenOpenInverse is the OPEN_INVERSE token
47 | TokenOpenInverse
48 |
49 | // TokenOpenInverseChain is the OPEN_INVERSE_CHAIN token
50 | TokenOpenInverseChain
51 |
52 | // TokenOpenPartial is the OPEN_PARTIAL token
53 | TokenOpenPartial
54 |
55 | // TokenComment is the COMMENT token
56 | TokenComment
57 |
58 | //
59 | // Inside mustaches
60 | //
61 |
62 | // TokenOpenSexpr is the OPEN_SEXPR token
63 | TokenOpenSexpr
64 |
65 | // TokenCloseSexpr is the CLOSE_SEXPR token
66 | TokenCloseSexpr
67 |
68 | // TokenEquals is the EQUALS token
69 | TokenEquals
70 |
71 | // TokenData is the DATA token
72 | TokenData
73 |
74 | // TokenSep is the SEP token
75 | TokenSep
76 |
77 | // TokenOpenBlockParams is the OPEN_BLOCK_PARAMS token
78 | TokenOpenBlockParams
79 |
80 | // TokenCloseBlockParams is the CLOSE_BLOCK_PARAMS token
81 | TokenCloseBlockParams
82 |
83 | //
84 | // Tokens with content
85 | //
86 |
87 | // TokenContent is the CONTENT token
88 | TokenContent
89 |
90 | // TokenID is the ID token
91 | TokenID
92 |
93 | // TokenString is the STRING token
94 | TokenString
95 |
96 | // TokenNumber is the NUMBER token
97 | TokenNumber
98 |
99 | // TokenBoolean is the BOOLEAN token
100 | TokenBoolean
101 | )
102 |
103 | const (
104 | // Option to generate token position in its string representation
105 | dumpTokenPos = false
106 |
107 | // Option to generate values for all token kinds for their string representations
108 | dumpAllTokensVal = true
109 | )
110 |
111 | // TokenKind represents a Token type.
112 | type TokenKind int
113 |
114 | // Token represents a scanned token.
115 | type Token struct {
116 | Kind TokenKind // Token kind
117 | Val string // Token value
118 |
119 | Pos int // Byte position in input string
120 | Line int // Line number in input string
121 | }
122 |
123 | // tokenName permits to display token name given token type
124 | var tokenName = map[TokenKind]string{
125 | TokenError: "Error",
126 | TokenEOF: "EOF",
127 | TokenContent: "Content",
128 | TokenComment: "Comment",
129 | TokenOpen: "Open",
130 | TokenClose: "Close",
131 | TokenOpenUnescaped: "OpenUnescaped",
132 | TokenCloseUnescaped: "CloseUnescaped",
133 | TokenOpenBlock: "OpenBlock",
134 | TokenOpenEndBlock: "OpenEndBlock",
135 | TokenOpenRawBlock: "OpenRawBlock",
136 | TokenCloseRawBlock: "CloseRawBlock",
137 | TokenOpenEndRawBlock: "OpenEndRawBlock",
138 | TokenOpenBlockParams: "OpenBlockParams",
139 | TokenCloseBlockParams: "CloseBlockParams",
140 | TokenInverse: "Inverse",
141 | TokenOpenInverse: "OpenInverse",
142 | TokenOpenInverseChain: "OpenInverseChain",
143 | TokenOpenPartial: "OpenPartial",
144 | TokenOpenSexpr: "OpenSexpr",
145 | TokenCloseSexpr: "CloseSexpr",
146 | TokenID: "ID",
147 | TokenEquals: "Equals",
148 | TokenString: "String",
149 | TokenNumber: "Number",
150 | TokenBoolean: "Boolean",
151 | TokenData: "Data",
152 | TokenSep: "Sep",
153 | }
154 |
155 | // String returns the token kind string representation for debugging.
156 | func (k TokenKind) String() string {
157 | s := tokenName[k]
158 | if s == "" {
159 | return fmt.Sprintf("Token-%d", int(k))
160 | }
161 | return s
162 | }
163 |
164 | // String returns the token string representation for debugging.
165 | func (t Token) String() string {
166 | result := ""
167 |
168 | if dumpTokenPos {
169 | result += fmt.Sprintf("%d:", t.Pos)
170 | }
171 |
172 | result += fmt.Sprintf("%s", t.Kind)
173 |
174 | if (dumpAllTokensVal || (t.Kind >= TokenContent)) && len(t.Val) > 0 {
175 | if len(t.Val) > 100 {
176 | result += fmt.Sprintf("{%.20q...}", t.Val)
177 | } else {
178 | result += fmt.Sprintf("{%q}", t.Val)
179 | }
180 | }
181 |
182 | return result
183 | }
184 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/Changes:
--------------------------------------------------------------------------------
1 | 2011-03-20: v1.1.2
2 | Added tests for standalone tags at string boundaries.
3 | Added tests for rendering lambda returns after delimiter changes.
4 |
5 | 2011-03-20: v1.0.3
6 | Added tests for standalone tags at string boundaries.
7 | Added tests for rendering lambda returns after delimiter changes.
8 |
9 | 2011-03-05: v1.1.1
10 | Added tests for indented inline sections.
11 | Added tests for Windows-style newlines.
12 |
13 | 2011-03-05: v1.0.2
14 | Added tests for indented inline sections.
15 | Added tests for Windows-style newlines.
16 |
17 | 2011-03-04: v1.1.0
18 | Implicit iterators.
19 | A single period (`.`) may now be used as a name in Interpolation tags,
20 | which represents the top of stack (cast as a String).
21 | Dotted names.
22 | Names containing one or more periods should be resolved as chained
23 | properties; naïvely, this is like nesting section tags, but with some
24 | built-in scoping protections.
25 |
26 | 2011-03-02: v1.0.1
27 | Clarifying a point in the README about version compliance.
28 | Adding high-level documentation to each spec file.
29 |
30 | 2011-02-28: v1.0.0
31 | Initial Release
32 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/Rakefile:
--------------------------------------------------------------------------------
1 | require 'json'
2 | require 'yaml'
3 |
4 | # Our custom YAML tags must retain their magic.
5 | %w[ code ].each do |tag|
6 | YAML::add_builtin_type(tag) { |_,val| val.merge(:__tag__ => tag) }
7 | end
8 |
9 | desc 'Build all alternate versions of the specs.'
10 | multitask :build => [ 'build:json' ]
11 |
12 | namespace :build do
13 | note = 'Do not edit this file; changes belong in the appropriate YAML file.'
14 |
15 | desc 'Build JSON versions of the specs.'
16 | task :json do
17 | rm(Dir['specs/*.json'], :verbose => false)
18 | Dir.glob('specs/*.yml').each do |filename|
19 | json_file = filename.gsub('.yml', '.json')
20 |
21 | File.open(json_file, 'w') do |file|
22 | doc = YAML.load_file(filename)
23 | file << doc.merge(:__ATTN__ => note).to_json()
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/TESTING.md:
--------------------------------------------------------------------------------
1 | Testing your Mustache implementation against this specification should be
2 | relatively simple. If you have a readily available testing framework on your
3 | platform, your task may be even simpler.
4 |
5 | In general, the process for each `.yml` file is as follows:
6 |
7 | 1. Use a YAML parser to load the file.
8 |
9 | 2. For each test in the 'tests' array:
10 |
11 | 1. Ensure that each element of the 'partials' hash (if it exists) is
12 | stored in a place where the interpreter will look for it.
13 |
14 | 2. If your implementation will not support lambdas, feel free to skip over
15 | the optional '~lambdas.yml' file.
16 |
17 | 2.1. If your implementation will support lambdas, ensure that each member of
18 | 'data' tagged with '!code' is properly processed into a language-
19 | specific lambda reference.
20 |
21 | * e.g. Given this YAML data hash:
22 |
23 | `{ x: !code { ruby: 'proc { "x" }', perl: 'sub { "x" }' } }`
24 |
25 | a Ruby-based Mustache implementation would process it such that it
26 | was equivalent to this Ruby hash:
27 |
28 | `{ 'x' => proc { "x" } }`
29 |
30 | * If your implementation language does not currently have lambda
31 | examples in the spec, feel free to implement them and send a pull
32 | request.
33 |
34 | * The JSON version of the spec represents these tagged values as a hash
35 | with a '`__tag__`' key of 'code'.
36 |
37 | 3. Render the template (stored in the 'template' key) with the given 'data'
38 | hash.
39 |
40 | 4. Compare the results of your rendering against the 'expected' value; any
41 | differences should be reported, along with any useful debugging
42 | information.
43 |
44 | * Of note, the 'desc' key contains a rough one-line description of the
45 | behavior being tested -- this is most useful in conjunction with the
46 | file name and test 'name'.
47 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/specs/comments.json:
--------------------------------------------------------------------------------
1 | {"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Comment tags represent content that should never appear in the resulting\noutput.\n\nThe tag's content may contain any substring (including newlines) EXCEPT the\nclosing delimiter.\n\nComment tags SHOULD be treated as standalone when appropriate.\n","tests":[{"name":"Inline","data":{},"expected":"1234567890","template":"12345{{! Comment Block! }}67890","desc":"Comment blocks should be removed from the template."},{"name":"Multiline","data":{},"expected":"1234567890\n","template":"12345{{!\n This is a\n multi-line comment...\n}}67890\n","desc":"Multiline comments should be permitted."},{"name":"Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{! Comment Block! }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{! Indented Comment Block! }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n|","template":"|\r\n{{! Standalone Comment }}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{},"expected":"!","template":" {{! I'm Still Standalone }}\n!","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{},"expected":"!\n","template":"!\n {{! I'm Still Standalone }}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Multiline Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Multiline Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{!\n Something's going on here...\n }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Inline","data":{},"expected":" 12 \n","template":" 12 {{! 34 }}\n","desc":"Inline comments should not strip whitespace"},{"name":"Surrounding Whitespace","data":{},"expected":"12345 67890","template":"12345 {{! Comment Block! }} 67890","desc":"Comment removal should preserve surrounding whitespace."}]}
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/specs/comments.yml:
--------------------------------------------------------------------------------
1 | overview: |
2 | Comment tags represent content that should never appear in the resulting
3 | output.
4 |
5 | The tag's content may contain any substring (including newlines) EXCEPT the
6 | closing delimiter.
7 |
8 | Comment tags SHOULD be treated as standalone when appropriate.
9 | tests:
10 | - name: Inline
11 | desc: Comment blocks should be removed from the template.
12 | data: { }
13 | template: '12345{{! Comment Block! }}67890'
14 | expected: '1234567890'
15 |
16 | - name: Multiline
17 | desc: Multiline comments should be permitted.
18 | data: { }
19 | template: |
20 | 12345{{!
21 | This is a
22 | multi-line comment...
23 | }}67890
24 | expected: |
25 | 1234567890
26 |
27 | - name: Standalone
28 | desc: All standalone comment lines should be removed.
29 | data: { }
30 | template: |
31 | Begin.
32 | {{! Comment Block! }}
33 | End.
34 | expected: |
35 | Begin.
36 | End.
37 |
38 | - name: Indented Standalone
39 | desc: All standalone comment lines should be removed.
40 | data: { }
41 | template: |
42 | Begin.
43 | {{! Indented Comment Block! }}
44 | End.
45 | expected: |
46 | Begin.
47 | End.
48 |
49 | - name: Standalone Line Endings
50 | desc: '"\r\n" should be considered a newline for standalone tags.'
51 | data: { }
52 | template: "|\r\n{{! Standalone Comment }}\r\n|"
53 | expected: "|\r\n|"
54 |
55 | - name: Standalone Without Previous Line
56 | desc: Standalone tags should not require a newline to precede them.
57 | data: { }
58 | template: " {{! I'm Still Standalone }}\n!"
59 | expected: "!"
60 |
61 | - name: Standalone Without Newline
62 | desc: Standalone tags should not require a newline to follow them.
63 | data: { }
64 | template: "!\n {{! I'm Still Standalone }}"
65 | expected: "!\n"
66 |
67 | - name: Multiline Standalone
68 | desc: All standalone comment lines should be removed.
69 | data: { }
70 | template: |
71 | Begin.
72 | {{!
73 | Something's going on here...
74 | }}
75 | End.
76 | expected: |
77 | Begin.
78 | End.
79 |
80 | - name: Indented Multiline Standalone
81 | desc: All standalone comment lines should be removed.
82 | data: { }
83 | template: |
84 | Begin.
85 | {{!
86 | Something's going on here...
87 | }}
88 | End.
89 | expected: |
90 | Begin.
91 | End.
92 |
93 | - name: Indented Inline
94 | desc: Inline comments should not strip whitespace
95 | data: { }
96 | template: " 12 {{! 34 }}\n"
97 | expected: " 12 \n"
98 |
99 | - name: Surrounding Whitespace
100 | desc: Comment removal should preserve surrounding whitespace.
101 | data: { }
102 | template: '12345 {{! Comment Block! }} 67890'
103 | expected: '12345 67890'
104 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/specs/delimiters.json:
--------------------------------------------------------------------------------
1 | {"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Set Delimiter tags are used to change the tag delimiters for all content\nfollowing the tag in the current compilation unit.\n\nThe tag's content MUST be any two non-whitespace sequences (separated by\nwhitespace) EXCEPT an equals sign ('=') followed by the current closing\ndelimiter.\n\nSet Delimiter tags SHOULD be treated as standalone when appropriate.\n","tests":[{"name":"Pair Behavior","data":{"text":"Hey!"},"expected":"(Hey!)","template":"{{=<% %>=}}(<%text%>)","desc":"The equals sign (used on both sides) should permit delimiter changes."},{"name":"Special Characters","data":{"text":"It worked!"},"expected":"(It worked!)","template":"({{=[ ]=}}[text])","desc":"Characters with special meaning regexen should be valid delimiters."},{"name":"Sections","data":{"section":true,"data":"I got interpolated."},"expected":"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n","template":"[\n{{#section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|#section|\n {{data}}\n |data|\n|/section|\n]\n","desc":"Delimiters set outside sections should persist."},{"name":"Inverted Sections","data":{"section":false,"data":"I got interpolated."},"expected":"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n","template":"[\n{{^section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|^section|\n {{data}}\n |data|\n|/section|\n]\n","desc":"Delimiters set outside inverted sections should persist."},{"name":"Partial Inheritence","data":{"value":"yes"},"expected":"[ .yes. ]\n[ .yes. ]\n","template":"[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n","desc":"Delimiters set in a parent template should not affect a partial.","partials":{"include":".{{value}}."}},{"name":"Post-Partial Behavior","data":{"value":"yes"},"expected":"[ .yes. .yes. ]\n[ .yes. .|value|. ]\n","template":"[ {{>include}} ]\n[ .{{value}}. .|value|. ]\n","desc":"Delimiters set in a partial should not affect the parent template.","partials":{"include":".{{value}}. {{= | | =}} .|value|."}},{"name":"Surrounding Whitespace","data":{},"expected":"| |","template":"| {{=@ @=}} |","desc":"Surrounding whitespace should be left untouched."},{"name":"Outlying Whitespace (Inline)","data":{},"expected":" | \n","template":" | {{=@ @=}}\n","desc":"Whitespace should be left untouched."},{"name":"Standalone Tag","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{=@ @=}}\nEnd.\n","desc":"Standalone lines should be removed from the template."},{"name":"Indented Standalone Tag","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{=@ @=}}\nEnd.\n","desc":"Indented standalone lines should be removed from the template."},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n|","template":"|\r\n{{= @ @ =}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{},"expected":"=","template":" {{=@ @=}}\n=","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{},"expected":"=\n","template":"=\n {{=@ @=}}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Pair with Padding","data":{},"expected":"||","template":"|{{= @ @ =}}|","desc":"Superfluous in-tag whitespace should be ignored."}]}
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/specs/delimiters.yml:
--------------------------------------------------------------------------------
1 | overview: |
2 | Set Delimiter tags are used to change the tag delimiters for all content
3 | following the tag in the current compilation unit.
4 |
5 | The tag's content MUST be any two non-whitespace sequences (separated by
6 | whitespace) EXCEPT an equals sign ('=') followed by the current closing
7 | delimiter.
8 |
9 | Set Delimiter tags SHOULD be treated as standalone when appropriate.
10 | tests:
11 | - name: Pair Behavior
12 | desc: The equals sign (used on both sides) should permit delimiter changes.
13 | data: { text: 'Hey!' }
14 | template: '{{=<% %>=}}(<%text%>)'
15 | expected: '(Hey!)'
16 |
17 | - name: Special Characters
18 | desc: Characters with special meaning regexen should be valid delimiters.
19 | data: { text: 'It worked!' }
20 | template: '({{=[ ]=}}[text])'
21 | expected: '(It worked!)'
22 |
23 | - name: Sections
24 | desc: Delimiters set outside sections should persist.
25 | data: { section: true, data: 'I got interpolated.' }
26 | template: |
27 | [
28 | {{#section}}
29 | {{data}}
30 | |data|
31 | {{/section}}
32 |
33 | {{= | | =}}
34 | |#section|
35 | {{data}}
36 | |data|
37 | |/section|
38 | ]
39 | expected: |
40 | [
41 | I got interpolated.
42 | |data|
43 |
44 | {{data}}
45 | I got interpolated.
46 | ]
47 |
48 | - name: Inverted Sections
49 | desc: Delimiters set outside inverted sections should persist.
50 | data: { section: false, data: 'I got interpolated.' }
51 | template: |
52 | [
53 | {{^section}}
54 | {{data}}
55 | |data|
56 | {{/section}}
57 |
58 | {{= | | =}}
59 | |^section|
60 | {{data}}
61 | |data|
62 | |/section|
63 | ]
64 | expected: |
65 | [
66 | I got interpolated.
67 | |data|
68 |
69 | {{data}}
70 | I got interpolated.
71 | ]
72 |
73 | - name: Partial Inheritence
74 | desc: Delimiters set in a parent template should not affect a partial.
75 | data: { value: 'yes' }
76 | partials:
77 | include: '.{{value}}.'
78 | template: |
79 | [ {{>include}} ]
80 | {{= | | =}}
81 | [ |>include| ]
82 | expected: |
83 | [ .yes. ]
84 | [ .yes. ]
85 |
86 | - name: Post-Partial Behavior
87 | desc: Delimiters set in a partial should not affect the parent template.
88 | data: { value: 'yes' }
89 | partials:
90 | include: '.{{value}}. {{= | | =}} .|value|.'
91 | template: |
92 | [ {{>include}} ]
93 | [ .{{value}}. .|value|. ]
94 | expected: |
95 | [ .yes. .yes. ]
96 | [ .yes. .|value|. ]
97 |
98 | # Whitespace Sensitivity
99 |
100 | - name: Surrounding Whitespace
101 | desc: Surrounding whitespace should be left untouched.
102 | data: { }
103 | template: '| {{=@ @=}} |'
104 | expected: '| |'
105 |
106 | - name: Outlying Whitespace (Inline)
107 | desc: Whitespace should be left untouched.
108 | data: { }
109 | template: " | {{=@ @=}}\n"
110 | expected: " | \n"
111 |
112 | - name: Standalone Tag
113 | desc: Standalone lines should be removed from the template.
114 | data: { }
115 | template: |
116 | Begin.
117 | {{=@ @=}}
118 | End.
119 | expected: |
120 | Begin.
121 | End.
122 |
123 | - name: Indented Standalone Tag
124 | desc: Indented standalone lines should be removed from the template.
125 | data: { }
126 | template: |
127 | Begin.
128 | {{=@ @=}}
129 | End.
130 | expected: |
131 | Begin.
132 | End.
133 |
134 | - name: Standalone Line Endings
135 | desc: '"\r\n" should be considered a newline for standalone tags.'
136 | data: { }
137 | template: "|\r\n{{= @ @ =}}\r\n|"
138 | expected: "|\r\n|"
139 |
140 | - name: Standalone Without Previous Line
141 | desc: Standalone tags should not require a newline to precede them.
142 | data: { }
143 | template: " {{=@ @=}}\n="
144 | expected: "="
145 |
146 | - name: Standalone Without Newline
147 | desc: Standalone tags should not require a newline to follow them.
148 | data: { }
149 | template: "=\n {{=@ @=}}"
150 | expected: "=\n"
151 |
152 | # Whitespace Insensitivity
153 |
154 | - name: Pair with Padding
155 | desc: Superfluous in-tag whitespace should be ignored.
156 | data: { }
157 | template: '|{{= @ @ =}}|'
158 | expected: '||'
159 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/specs/partials.json:
--------------------------------------------------------------------------------
1 | {"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Partial tags are used to expand an external template into the current\ntemplate.\n\nThe tag's content MUST be a non-whitespace character sequence NOT containing\nthe current closing delimiter.\n\nThis tag's content names the partial to inject. Set Delimiter tags MUST NOT\naffect the parsing of a partial. The partial MUST be rendered against the\ncontext stack local to the tag. If the named partial cannot be found, the\nempty string SHOULD be used instead, as in interpolations.\n\nPartial tags SHOULD be treated as standalone when appropriate. If this tag\nis used standalone, any whitespace preceding the tag should treated as\nindentation, and prepended to each line of the partial before rendering.\n","tests":[{"name":"Basic Behavior","data":{},"expected":"\"from partial\"","template":"\"{{>text}}\"","desc":"The greater-than operator should expand to the named partial.","partials":{"text":"from partial"}},{"name":"Failed Lookup","data":{},"expected":"\"\"","template":"\"{{>text}}\"","desc":"The empty string should be used when the named partial is not found.","partials":{}},{"name":"Context","data":{"text":"content"},"expected":"\"*content*\"","template":"\"{{>partial}}\"","desc":"The greater-than operator should operate within the current context.","partials":{"partial":"*{{text}}*"}},{"name":"Recursion","data":{"content":"X","nodes":[{"content":"Y","nodes":[]}]},"expected":"X>","template":"{{>node}}","desc":"The greater-than operator should properly recurse.","partials":{"node":"{{content}}<{{#nodes}}{{>node}}{{/nodes}}>"}},{"name":"Surrounding Whitespace","data":{},"expected":"| \t|\t |","template":"| {{>partial}} |","desc":"The greater-than operator should not alter surrounding whitespace.","partials":{"partial":"\t|\t"}},{"name":"Inline Indentation","data":{"data":"|"},"expected":" | >\n>\n","template":" {{data}} {{> partial}}\n","desc":"Whitespace should be left untouched.","partials":{"partial":">\n>"}},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n>|","template":"|\r\n{{>partial}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags.","partials":{"partial":">"}},{"name":"Standalone Without Previous Line","data":{},"expected":" >\n >>","template":" {{>partial}}\n>","desc":"Standalone tags should not require a newline to precede them.","partials":{"partial":">\n>"}},{"name":"Standalone Without Newline","data":{},"expected":">\n >\n >","template":">\n {{>partial}}","desc":"Standalone tags should not require a newline to follow them.","partials":{"partial":">\n>"}},{"name":"Standalone Indentation","data":{"content":"<\n->"},"expected":"\\\n |\n <\n->\n |\n/\n","template":"\\\n {{>partial}}\n/\n","desc":"Each line of the partial should be indented before rendering.","partials":{"partial":"|\n{{{content}}}\n|\n"}},{"name":"Padding Whitespace","data":{"boolean":true},"expected":"|[]|","template":"|{{> partial }}|","desc":"Superfluous in-tag whitespace should be ignored.","partials":{"partial":"[]"}}]}
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/specs/partials.yml:
--------------------------------------------------------------------------------
1 | overview: |
2 | Partial tags are used to expand an external template into the current
3 | template.
4 |
5 | The tag's content MUST be a non-whitespace character sequence NOT containing
6 | the current closing delimiter.
7 |
8 | This tag's content names the partial to inject. Set Delimiter tags MUST NOT
9 | affect the parsing of a partial. The partial MUST be rendered against the
10 | context stack local to the tag. If the named partial cannot be found, the
11 | empty string SHOULD be used instead, as in interpolations.
12 |
13 | Partial tags SHOULD be treated as standalone when appropriate. If this tag
14 | is used standalone, any whitespace preceding the tag should treated as
15 | indentation, and prepended to each line of the partial before rendering.
16 | tests:
17 | - name: Basic Behavior
18 | desc: The greater-than operator should expand to the named partial.
19 | data: { }
20 | template: '"{{>text}}"'
21 | partials: { text: 'from partial' }
22 | expected: '"from partial"'
23 |
24 | - name: Failed Lookup
25 | desc: The empty string should be used when the named partial is not found.
26 | data: { }
27 | template: '"{{>text}}"'
28 | partials: { }
29 | expected: '""'
30 |
31 | - name: Context
32 | desc: The greater-than operator should operate within the current context.
33 | data: { text: 'content' }
34 | template: '"{{>partial}}"'
35 | partials: { partial: '*{{text}}*' }
36 | expected: '"*content*"'
37 |
38 | - name: Recursion
39 | desc: The greater-than operator should properly recurse.
40 | data: { content: "X", nodes: [ { content: "Y", nodes: [] } ] }
41 | template: '{{>node}}'
42 | partials: { node: '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' }
43 | expected: 'X>'
44 |
45 | # Whitespace Sensitivity
46 |
47 | - name: Surrounding Whitespace
48 | desc: The greater-than operator should not alter surrounding whitespace.
49 | data: { }
50 | template: '| {{>partial}} |'
51 | partials: { partial: "\t|\t" }
52 | expected: "| \t|\t |"
53 |
54 | - name: Inline Indentation
55 | desc: Whitespace should be left untouched.
56 | data: { data: '|' }
57 | template: " {{data}} {{> partial}}\n"
58 | partials: { partial: ">\n>" }
59 | expected: " | >\n>\n"
60 |
61 | - name: Standalone Line Endings
62 | desc: '"\r\n" should be considered a newline for standalone tags.'
63 | data: { }
64 | template: "|\r\n{{>partial}}\r\n|"
65 | partials: { partial: ">" }
66 | expected: "|\r\n>|"
67 |
68 | - name: Standalone Without Previous Line
69 | desc: Standalone tags should not require a newline to precede them.
70 | data: { }
71 | template: " {{>partial}}\n>"
72 | partials: { partial: ">\n>"}
73 | expected: " >\n >>"
74 |
75 | - name: Standalone Without Newline
76 | desc: Standalone tags should not require a newline to follow them.
77 | data: { }
78 | template: ">\n {{>partial}}"
79 | partials: { partial: ">\n>" }
80 | expected: ">\n >\n >"
81 |
82 | - name: Standalone Indentation
83 | desc: Each line of the partial should be indented before rendering.
84 | data: { content: "<\n->" }
85 | template: |
86 | \
87 | {{>partial}}
88 | /
89 | partials:
90 | partial: |
91 | |
92 | {{{content}}}
93 | |
94 | expected: |
95 | \
96 | |
97 | <
98 | ->
99 | |
100 | /
101 |
102 | # Whitespace Insensitivity
103 |
104 | - name: Padding Whitespace
105 | desc: Superfluous in-tag whitespace should be ignored.
106 | data: { boolean: true }
107 | template: "|{{> partial }}|"
108 | partials: { partial: "[]" }
109 | expected: '|[]|'
110 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/mustache/specs/~lambdas.json:
--------------------------------------------------------------------------------
1 | {"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Lambdas are a special-cased data type for use in interpolations and\nsections.\n\nWhen used as the data value for an Interpolation tag, the lambda MUST be\ntreatable as an arity 0 function, and invoked as such. The returned value\nMUST be rendered against the default delimiters, then interpolated in place\nof the lambda.\n\nWhen used as the data value for a Section tag, the lambda MUST be treatable\nas an arity 1 function, and invoked as such (passing a String containing the\nunprocessed section contents). The returned value MUST be rendered against\nthe current delimiters, then interpolated in place of the section.\n","tests":[{"name":"Interpolation","data":{"lambda":{"php":"return \"world\";","clojure":"(fn [] \"world\")","__tag__":"code","perl":"sub { \"world\" }","python":"lambda: \"world\"","ruby":"proc { \"world\" }","js":"function() { return \"world\" }"}},"expected":"Hello, world!","template":"Hello, {{lambda}}!","desc":"A lambda's return value should be interpolated."},{"name":"Interpolation - Expansion","data":{"planet":"world","lambda":{"php":"return \"{{planet}}\";","clojure":"(fn [] \"{{planet}}\")","__tag__":"code","perl":"sub { \"{{planet}}\" }","python":"lambda: \"{{planet}}\"","ruby":"proc { \"{{planet}}\" }","js":"function() { return \"{{planet}}\" }"}},"expected":"Hello, world!","template":"Hello, {{lambda}}!","desc":"A lambda's return value should be parsed."},{"name":"Interpolation - Alternate Delimiters","data":{"planet":"world","lambda":{"php":"return \"|planet| => {{planet}}\";","clojure":"(fn [] \"|planet| => {{planet}}\")","__tag__":"code","perl":"sub { \"|planet| => {{planet}}\" }","python":"lambda: \"|planet| => {{planet}}\"","ruby":"proc { \"|planet| => {{planet}}\" }","js":"function() { return \"|planet| => {{planet}}\" }"}},"expected":"Hello, (|planet| => world)!","template":"{{= | | =}}\nHello, (|&lambda|)!","desc":"A lambda's return value should parse with the default delimiters."},{"name":"Interpolation - Multiple Calls","data":{"lambda":{"php":"global $calls; return ++$calls;","clojure":"(def g (atom 0)) (fn [] (swap! g inc))","__tag__":"code","perl":"sub { no strict; $calls += 1 }","python":"lambda: globals().update(calls=globals().get(\"calls\",0)+1) or calls","ruby":"proc { $calls ||= 0; $calls += 1 }","js":"function() { return (g=(function(){return this})()).calls=(g.calls||0)+1 }"}},"expected":"1 == 2 == 3","template":"{{lambda}} == {{{lambda}}} == {{lambda}}","desc":"Interpolated lambdas should not be cached."},{"name":"Escaping","data":{"lambda":{"php":"return \">\";","clojure":"(fn [] \">\")","__tag__":"code","perl":"sub { \">\" }","python":"lambda: \">\"","ruby":"proc { \">\" }","js":"function() { return \">\" }"}},"expected":"<>>","template":"<{{lambda}}{{{lambda}}}","desc":"Lambda results should be appropriately escaped."},{"name":"Section","data":{"x":"Error!","lambda":{"php":"return ($text == \"{{x}}\") ? \"yes\" : \"no\";","clojure":"(fn [text] (if (= text \"{{x}}\") \"yes\" \"no\"))","__tag__":"code","perl":"sub { $_[0] eq \"{{x}}\" ? \"yes\" : \"no\" }","python":"lambda text: text == \"{{x}}\" and \"yes\" or \"no\"","ruby":"proc { |text| text == \"{{x}}\" ? \"yes\" : \"no\" }","js":"function(txt) { return (txt == \"{{x}}\" ? \"yes\" : \"no\") }"}},"expected":"","template":"<{{#lambda}}{{x}}{{/lambda}}>","desc":"Lambdas used for sections should receive the raw section string."},{"name":"Section - Expansion","data":{"planet":"Earth","lambda":{"php":"return $text . \"{{planet}}\" . $text;","clojure":"(fn [text] (str text \"{{planet}}\" text))","__tag__":"code","perl":"sub { $_[0] . \"{{planet}}\" . $_[0] }","python":"lambda text: \"%s{{planet}}%s\" % (text, text)","ruby":"proc { |text| \"#{text}{{planet}}#{text}\" }","js":"function(txt) { return txt + \"{{planet}}\" + txt }"}},"expected":"<-Earth->","template":"<{{#lambda}}-{{/lambda}}>","desc":"Lambdas used for sections should have their results parsed."},{"name":"Section - Alternate Delimiters","data":{"planet":"Earth","lambda":{"php":"return $text . \"{{planet}} => |planet|\" . $text;","clojure":"(fn [text] (str text \"{{planet}} => |planet|\" text))","__tag__":"code","perl":"sub { $_[0] . \"{{planet}} => |planet|\" . $_[0] }","python":"lambda text: \"%s{{planet}} => |planet|%s\" % (text, text)","ruby":"proc { |text| \"#{text}{{planet}} => |planet|#{text}\" }","js":"function(txt) { return txt + \"{{planet}} => |planet|\" + txt }"}},"expected":"<-{{planet}} => Earth->","template":"{{= | | =}}<|#lambda|-|/lambda|>","desc":"Lambdas used for sections should parse with the current delimiters."},{"name":"Section - Multiple Calls","data":{"lambda":{"php":"return \"__\" . $text . \"__\";","clojure":"(fn [text] (str \"__\" text \"__\"))","__tag__":"code","perl":"sub { \"__\" . $_[0] . \"__\" }","python":"lambda text: \"__%s__\" % (text)","ruby":"proc { |text| \"__#{text}__\" }","js":"function(txt) { return \"__\" + txt + \"__\" }"}},"expected":"__FILE__ != __LINE__","template":"{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}","desc":"Lambdas used for sections should not be cached."},{"name":"Inverted Section","data":{"static":"static","lambda":{"php":"return false;","clojure":"(fn [text] false)","__tag__":"code","perl":"sub { 0 }","python":"lambda text: 0","ruby":"proc { |text| false }","js":"function(txt) { return false }"}},"expected":"<>","template":"<{{^lambda}}{{static}}{{/lambda}}>","desc":"Lambdas used for inverted sections should be considered truthy."}]}
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/partial.go:
--------------------------------------------------------------------------------
1 | package raymond
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | )
7 |
8 | // partial represents a partial template
9 | type partial struct {
10 | name string
11 | source string
12 | tpl *Template
13 | }
14 |
15 | // partials stores all global partials
16 | var partials map[string]*partial
17 |
18 | // protects global partials
19 | var partialsMutex sync.RWMutex
20 |
21 | func init() {
22 | partials = make(map[string]*partial)
23 | }
24 |
25 | // newPartial instanciates a new partial
26 | func newPartial(name string, source string, tpl *Template) *partial {
27 | return &partial{
28 | name: name,
29 | source: source,
30 | tpl: tpl,
31 | }
32 | }
33 |
34 | // RegisterPartial registers a global partial. That partial will be available to all templates.
35 | func RegisterPartial(name string, source string) {
36 | partialsMutex.Lock()
37 | defer partialsMutex.Unlock()
38 |
39 | if partials[name] != nil {
40 | panic(fmt.Errorf("Partial already registered: %s", name))
41 | }
42 |
43 | partials[name] = newPartial(name, source, nil)
44 | }
45 |
46 | // RegisterPartials registers several global partials. Those partials will be available to all templates.
47 | func RegisterPartials(partials map[string]string) {
48 | for name, p := range partials {
49 | RegisterPartial(name, p)
50 | }
51 | }
52 |
53 | // RegisterPartialTemplate registers a global partial with given parsed template. That partial will be available to all templates.
54 | func RegisterPartialTemplate(name string, tpl *Template) {
55 | partialsMutex.Lock()
56 | defer partialsMutex.Unlock()
57 |
58 | if partials[name] != nil {
59 | panic(fmt.Errorf("Partial already registered: %s", name))
60 | }
61 |
62 | partials[name] = newPartial(name, "", tpl)
63 | }
64 |
65 | // findPartial finds a registered global partial
66 | func findPartial(name string) *partial {
67 | partialsMutex.RLock()
68 | defer partialsMutex.RUnlock()
69 |
70 | return partials[name]
71 | }
72 |
73 | // template returns parsed partial template
74 | func (p *partial) template() (*Template, error) {
75 | if p.tpl == nil {
76 | var err error
77 |
78 | p.tpl, err = Parse(p.source)
79 | if err != nil {
80 | return nil, err
81 | }
82 | }
83 |
84 | return p.tpl, nil
85 | }
86 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/raymond.go:
--------------------------------------------------------------------------------
1 | // Package raymond provides handlebars evaluation
2 | package raymond
3 |
4 | // Render parses a template and evaluates it with given context
5 | //
6 | // Note that this function call is not optimal as your template is parsed everytime you call it. You should use Parse() function instead.
7 | func Render(source string, ctx interface{}) (string, error) {
8 | // parse template
9 | tpl, err := Parse(source)
10 | if err != nil {
11 | return "", err
12 | }
13 |
14 | // renders template
15 | str, err := tpl.Exec(ctx)
16 | if err != nil {
17 | return "", err
18 | }
19 |
20 | return str, nil
21 | }
22 |
23 | // MustRender parses a template and evaluates it with given context. It panics on error.
24 | //
25 | // Note that this function call is not optimal as your template is parsed everytime you call it. You should use Parse() function instead.
26 | func MustRender(source string, ctx interface{}) string {
27 | return MustParse(source).MustExec(ctx)
28 | }
29 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/string.go:
--------------------------------------------------------------------------------
1 | package raymond
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | "strconv"
7 | )
8 |
9 | // SafeString represents a string that must not be escaped.
10 | //
11 | // A SafeString can be returned by helpers to disable escaping.
12 | type SafeString string
13 |
14 | // isSafeString returns true if argument is a SafeString
15 | func isSafeString(value interface{}) bool {
16 | if _, ok := value.(SafeString); ok {
17 | return true
18 | }
19 | return false
20 | }
21 |
22 | // Str returns string representation of any basic type value.
23 | func Str(value interface{}) string {
24 | return strValue(reflect.ValueOf(value))
25 | }
26 |
27 | // strValue returns string representation of a reflect.Value
28 | func strValue(value reflect.Value) string {
29 | result := ""
30 |
31 | ival, ok := printableValue(value)
32 | if !ok {
33 | panic(fmt.Errorf("Can't print value: %q", value))
34 | }
35 |
36 | val := reflect.ValueOf(ival)
37 |
38 | switch val.Kind() {
39 | case reflect.Array, reflect.Slice:
40 | for i := 0; i < val.Len(); i++ {
41 | result += strValue(val.Index(i))
42 | }
43 | case reflect.Bool:
44 | result = "false"
45 | if val.Bool() {
46 | result = "true"
47 | }
48 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
49 | result = fmt.Sprintf("%d", ival)
50 | case reflect.Float32, reflect.Float64:
51 | result = strconv.FormatFloat(val.Float(), 'f', -1, 64)
52 | case reflect.Invalid:
53 | result = ""
54 | default:
55 | result = fmt.Sprintf("%s", ival)
56 | }
57 |
58 | return result
59 | }
60 |
61 | // printableValue returns the, possibly indirected, interface value inside v that
62 | // is best for a call to formatted printer.
63 | //
64 | // NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
65 | func printableValue(v reflect.Value) (interface{}, bool) {
66 | if v.Kind() == reflect.Ptr {
67 | v, _ = indirect(v) // fmt.Fprint handles nil.
68 | }
69 | if !v.IsValid() {
70 | return "", true
71 | }
72 |
73 | if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
74 | if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
75 | v = v.Addr()
76 | } else {
77 | switch v.Kind() {
78 | case reflect.Chan, reflect.Func:
79 | return nil, false
80 | }
81 | }
82 | }
83 | return v.Interface(), true
84 | }
85 |
--------------------------------------------------------------------------------
/vendor/github.com/aymerick/raymond/utils.go:
--------------------------------------------------------------------------------
1 | package raymond
2 |
3 | import (
4 | "path"
5 | "reflect"
6 | )
7 |
8 | // indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
9 | // We indirect through pointers and empty interfaces (only) because
10 | // non-empty interfaces have methods we might need.
11 | //
12 | // NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
13 | func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
14 | for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
15 | if v.IsNil() {
16 | return v, true
17 | }
18 | if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
19 | break
20 | }
21 | }
22 | return v, false
23 | }
24 |
25 | // IsTrue returns true if obj is a truthy value.
26 | func IsTrue(obj interface{}) bool {
27 | thruth, ok := isTrueValue(reflect.ValueOf(obj))
28 | if !ok {
29 | return false
30 | }
31 | return thruth
32 | }
33 |
34 | // isTrueValue reports whether the value is 'true', in the sense of not the zero of its type,
35 | // and whether the value has a meaningful truth value
36 | //
37 | // NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
38 | func isTrueValue(val reflect.Value) (truth, ok bool) {
39 | if !val.IsValid() {
40 | // Something like var x interface{}, never set. It's a form of nil.
41 | return false, true
42 | }
43 | switch val.Kind() {
44 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
45 | truth = val.Len() > 0
46 | case reflect.Bool:
47 | truth = val.Bool()
48 | case reflect.Complex64, reflect.Complex128:
49 | truth = val.Complex() != 0
50 | case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
51 | truth = !val.IsNil()
52 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
53 | truth = val.Int() != 0
54 | case reflect.Float32, reflect.Float64:
55 | truth = val.Float() != 0
56 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
57 | truth = val.Uint() != 0
58 | case reflect.Struct:
59 | truth = true // Struct values are always true.
60 | default:
61 | return
62 | }
63 | return truth, true
64 | }
65 |
66 | // canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
67 | //
68 | // NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
69 | func canBeNil(typ reflect.Type) bool {
70 | switch typ.Kind() {
71 | case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
72 | return true
73 | }
74 | return false
75 | }
76 |
77 | // fileBase returns base file name
78 | //
79 | // example: /foo/bar/baz.png => baz
80 | func fileBase(filePath string) string {
81 | fileName := path.Base(filePath)
82 | fileExt := path.Ext(filePath)
83 |
84 | return fileName[:len(fileName)-len(fileExt)]
85 | }
86 |
--------------------------------------------------------------------------------
/vendor/github.com/eknkc/amber/amberc/cli.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | amber "github.com/eknkc/amber"
7 | "os"
8 | )
9 |
10 | var prettyPrint bool
11 | var lineNumbers bool
12 |
13 | func init() {
14 | flag.BoolVar(&prettyPrint, "prettyprint", true, "Use pretty indentation in output html.")
15 | flag.BoolVar(&prettyPrint, "pp", true, "Use pretty indentation in output html.")
16 |
17 | flag.BoolVar(&lineNumbers, "linenos", true, "Enable debugging information in output html.")
18 | flag.BoolVar(&lineNumbers, "ln", true, "Enable debugging information in output html.")
19 |
20 | flag.Parse()
21 | }
22 |
23 | func main() {
24 | input := flag.Arg(0)
25 |
26 | if len(input) == 0 {
27 | fmt.Fprintln(os.Stderr, "Please provide an input file. (amberc input.amber)")
28 | os.Exit(1)
29 | }
30 |
31 | cmp := amber.New()
32 | cmp.PrettyPrint = prettyPrint
33 | cmp.LineNumbers = lineNumbers
34 |
35 | err := cmp.ParseFile(input)
36 |
37 | if err != nil {
38 | fmt.Fprintln(os.Stderr, err)
39 | os.Exit(1)
40 | }
41 |
42 | err = cmp.CompileWriter(os.Stdout)
43 |
44 | if err != nil {
45 | fmt.Fprintln(os.Stderr, err)
46 | os.Exit(1)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/AUTHORS:
--------------------------------------------------------------------------------
1 | Main author and maintainer of pongo2:
2 |
3 | * Florian Schlachter
4 |
5 | Contributors (in no specific order):
6 |
7 | * @romanoaugusto88
8 | * @vitalbh
9 |
10 | Feel free to add yourself to the list or to modify your entry if you did a contribution.
11 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2014 Florian Schlachter
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/context.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "fmt"
5 | "regexp"
6 | )
7 |
8 | var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$")
9 |
10 | // A Context type provides constants, variables, instances or functions to a template.
11 | //
12 | // pongo2 automatically provides meta-information or functions through the "pongo2"-key.
13 | // Currently, context["pongo2"] contains the following keys:
14 | // 1. version: returns the version string
15 | //
16 | // Template examples for accessing items from your context:
17 | // {{ myconstant }}
18 | // {{ myfunc("test", 42) }}
19 | // {{ user.name }}
20 | // {{ pongo2.version }}
21 | type Context map[string]interface{}
22 |
23 | func (c Context) checkForValidIdentifiers() *Error {
24 | for k, v := range c {
25 | if !reIdentifiers.MatchString(k) {
26 | return &Error{
27 | Sender: "checkForValidIdentifiers",
28 | ErrorMsg: fmt.Sprintf("Context-key '%s' (value: '%+v') is not a valid identifier.", k, v),
29 | }
30 | }
31 | }
32 | return nil
33 | }
34 |
35 | // Update updates this context with the key/value-pairs from another context.
36 | func (c Context) Update(other Context) Context {
37 | for k, v := range other {
38 | c[k] = v
39 | }
40 | return c
41 | }
42 |
43 | // ExecutionContext contains all data important for the current rendering state.
44 | //
45 | // If you're writing a custom tag, your tag's Execute()-function will
46 | // have access to the ExecutionContext. This struct stores anything
47 | // about the current rendering process's Context including
48 | // the Context provided by the user (field Public).
49 | // You can safely use the Private context to provide data to the user's
50 | // template (like a 'forloop'-information). The Shared-context is used
51 | // to share data between tags. All ExecutionContexts share this context.
52 | //
53 | // Please be careful when accessing the Public data.
54 | // PLEASE DO NOT MODIFY THE PUBLIC CONTEXT (read-only).
55 | //
56 | // To create your own execution context within tags, use the
57 | // NewChildExecutionContext(parent) function.
58 | type ExecutionContext struct {
59 | template *Template
60 |
61 | Autoescape bool
62 | Public Context
63 | Private Context
64 | Shared Context
65 | }
66 |
67 | var pongo2MetaContext = Context{
68 | "version": Version,
69 | }
70 |
71 | func newExecutionContext(tpl *Template, ctx Context) *ExecutionContext {
72 | privateCtx := make(Context)
73 |
74 | // Make the pongo2-related funcs/vars available to the context
75 | privateCtx["pongo2"] = pongo2MetaContext
76 |
77 | return &ExecutionContext{
78 | template: tpl,
79 |
80 | Public: ctx,
81 | Private: privateCtx,
82 | Autoescape: true,
83 | }
84 | }
85 |
86 | func NewChildExecutionContext(parent *ExecutionContext) *ExecutionContext {
87 | newctx := &ExecutionContext{
88 | template: parent.template,
89 |
90 | Public: parent.Public,
91 | Private: make(Context),
92 | Autoescape: parent.Autoescape,
93 | }
94 | newctx.Shared = parent.Shared
95 |
96 | // Copy all existing private items
97 | newctx.Private.Update(parent.Private)
98 |
99 | return newctx
100 | }
101 |
102 | func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
103 | filename := ctx.template.name
104 | var line, col int
105 | if token != nil {
106 | // No tokens available
107 | // TODO: Add location (from where?)
108 | filename = token.Filename
109 | line = token.Line
110 | col = token.Col
111 | }
112 | return &Error{
113 | Template: ctx.template,
114 | Filename: filename,
115 | Line: line,
116 | Column: col,
117 | Token: token,
118 | Sender: "execution",
119 | ErrorMsg: msg,
120 | }
121 | }
122 |
123 | func (ctx *ExecutionContext) Logf(format string, args ...interface{}) {
124 | ctx.template.set.logf(format, args...)
125 | }
126 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/doc.go:
--------------------------------------------------------------------------------
1 | // A Django-syntax like template-engine
2 | //
3 | // Blog posts about pongo2 (including introduction and migration):
4 | // https://www.florian-schlachter.de/?tag=pongo2
5 | //
6 | // Complete documentation on the template language:
7 | // https://docs.djangoproject.com/en/dev/topics/templates/
8 | //
9 | // Try out pongo2 live in the pongo2 playground:
10 | // https://www.florian-schlachter.de/pongo2/
11 | //
12 | // Make sure to read README.md in the repository as well.
13 | //
14 | // A tiny example with template strings:
15 | //
16 | // (Snippet on playground: https://www.florian-schlachter.de/pongo2/?id=1206546277)
17 | //
18 | // // Compile the template first (i. e. creating the AST)
19 | // tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
20 | // if err != nil {
21 | // panic(err)
22 | // }
23 | // // Now you can render the template with the given
24 | // // pongo2.Context how often you want to.
25 | // out, err := tpl.Execute(pongo2.Context{"name": "fred"})
26 | // if err != nil {
27 | // panic(err)
28 | // }
29 | // fmt.Println(out) // Output: Hello Fred!
30 | //
31 | package pongo2
32 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/error.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "os"
7 | )
8 |
9 | // The Error type is being used to address an error during lexing, parsing or
10 | // execution. If you want to return an error object (for example in your own
11 | // tag or filter) fill this object with as much information as you have.
12 | // Make sure "Sender" is always given (if you're returning an error within
13 | // a filter, make Sender equals 'filter:yourfilter'; same goes for tags: 'tag:mytag').
14 | // It's okay if you only fill in ErrorMsg if you don't have any other details at hand.
15 | type Error struct {
16 | Template *Template
17 | Filename string
18 | Line int
19 | Column int
20 | Token *Token
21 | Sender string
22 | ErrorMsg string
23 | }
24 |
25 | func (e *Error) updateFromTokenIfNeeded(template *Template, t *Token) *Error {
26 | if e.Template == nil {
27 | e.Template = template
28 | }
29 |
30 | if e.Token == nil {
31 | e.Token = t
32 | if e.Line <= 0 {
33 | e.Line = t.Line
34 | e.Column = t.Col
35 | }
36 | }
37 |
38 | return e
39 | }
40 |
41 | // Returns a nice formatted error string.
42 | func (e *Error) Error() string {
43 | s := "[Error"
44 | if e.Sender != "" {
45 | s += " (where: " + e.Sender + ")"
46 | }
47 | if e.Filename != "" {
48 | s += " in " + e.Filename
49 | }
50 | if e.Line > 0 {
51 | s += fmt.Sprintf(" | Line %d Col %d", e.Line, e.Column)
52 | if e.Token != nil {
53 | s += fmt.Sprintf(" near '%s'", e.Token.Val)
54 | }
55 | }
56 | s += "] "
57 | s += e.ErrorMsg
58 | return s
59 | }
60 |
61 | // RawLine returns the affected line from the original template, if available.
62 | func (e *Error) RawLine() (line string, available bool) {
63 | if e.Line <= 0 || e.Filename == "" {
64 | return "", false
65 | }
66 |
67 | filename := e.Filename
68 | if e.Template != nil {
69 | filename = e.Template.set.resolveFilename(e.Template, e.Filename)
70 | }
71 | file, err := os.Open(filename)
72 | if err != nil {
73 | panic(err)
74 | }
75 | defer func() {
76 | err := file.Close()
77 | if err != nil {
78 | panic(err)
79 | }
80 | }()
81 |
82 | scanner := bufio.NewScanner(file)
83 | l := 0
84 | for scanner.Scan() {
85 | l++
86 | if l == e.Line {
87 | return scanner.Text(), true
88 | }
89 | }
90 | return "", false
91 | }
92 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/filters.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | type FilterFunction func(in *Value, param *Value) (out *Value, err *Error)
8 |
9 | var filters map[string]FilterFunction
10 |
11 | func init() {
12 | filters = make(map[string]FilterFunction)
13 | }
14 |
15 | // Registers a new filter. If there's already a filter with the same
16 | // name, RegisterFilter will panic. You usually want to call this
17 | // function in the filter's init() function:
18 | // http://golang.org/doc/effective_go.html#init
19 | //
20 | // See http://www.florian-schlachter.de/post/pongo2/ for more about
21 | // writing filters and tags.
22 | func RegisterFilter(name string, fn FilterFunction) {
23 | _, existing := filters[name]
24 | if existing {
25 | panic(fmt.Sprintf("Filter with name '%s' is already registered.", name))
26 | }
27 | filters[name] = fn
28 | }
29 |
30 | // Replaces an already registered filter with a new implementation. Use this
31 | // function with caution since it allows you to change existing filter behaviour.
32 | func ReplaceFilter(name string, fn FilterFunction) {
33 | _, existing := filters[name]
34 | if !existing {
35 | panic(fmt.Sprintf("Filter with name '%s' does not exist (therefore cannot be overridden).", name))
36 | }
37 | filters[name] = fn
38 | }
39 |
40 | // Like ApplyFilter, but panics on an error
41 | func MustApplyFilter(name string, value *Value, param *Value) *Value {
42 | val, err := ApplyFilter(name, value, param)
43 | if err != nil {
44 | panic(err)
45 | }
46 | return val
47 | }
48 |
49 | // Applies a filter to a given value using the given parameters. Returns a *pongo2.Value or an error.
50 | func ApplyFilter(name string, value *Value, param *Value) (*Value, *Error) {
51 | fn, existing := filters[name]
52 | if !existing {
53 | return nil, &Error{
54 | Sender: "applyfilter",
55 | ErrorMsg: fmt.Sprintf("Filter with name '%s' not found.", name),
56 | }
57 | }
58 |
59 | // Make sure param is a *Value
60 | if param == nil {
61 | param = AsValue(nil)
62 | }
63 |
64 | return fn(value, param)
65 | }
66 |
67 | type filterCall struct {
68 | token *Token
69 |
70 | name string
71 | parameter IEvaluator
72 |
73 | filterFunc FilterFunction
74 | }
75 |
76 | func (fc *filterCall) Execute(v *Value, ctx *ExecutionContext) (*Value, *Error) {
77 | var param *Value
78 | var err *Error
79 |
80 | if fc.parameter != nil {
81 | param, err = fc.parameter.Evaluate(ctx)
82 | if err != nil {
83 | return nil, err
84 | }
85 | } else {
86 | param = AsValue(nil)
87 | }
88 |
89 | filteredValue, err := fc.filterFunc(v, param)
90 | if err != nil {
91 | return nil, err.updateFromTokenIfNeeded(ctx.template, fc.token)
92 | }
93 | return filteredValue, nil
94 | }
95 |
96 | // Filter = IDENT | IDENT ":" FilterArg | IDENT "|" Filter
97 | func (p *Parser) parseFilter() (*filterCall, *Error) {
98 | identToken := p.MatchType(TokenIdentifier)
99 |
100 | // Check filter ident
101 | if identToken == nil {
102 | return nil, p.Error("Filter name must be an identifier.", nil)
103 | }
104 |
105 | filter := &filterCall{
106 | token: identToken,
107 | name: identToken.Val,
108 | }
109 |
110 | // Get the appropriate filter function and bind it
111 | filterFn, exists := filters[identToken.Val]
112 | if !exists {
113 | return nil, p.Error(fmt.Sprintf("Filter '%s' does not exist.", identToken.Val), identToken)
114 | }
115 |
116 | filter.filterFunc = filterFn
117 |
118 | // Check for filter-argument (2 tokens needed: ':' ARG)
119 | if p.Match(TokenSymbol, ":") != nil {
120 | if p.Peek(TokenSymbol, "}}") != nil {
121 | return nil, p.Error("Filter parameter required after ':'.", nil)
122 | }
123 |
124 | // Get filter argument expression
125 | v, err := p.parseVariableOrLiteral()
126 | if err != nil {
127 | return nil, err
128 | }
129 | filter.parameter = v
130 | }
131 |
132 | return filter, nil
133 | }
134 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/helpers.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | func max(a, b int) int {
4 | if a > b {
5 | return a
6 | }
7 | return b
8 | }
9 |
10 | func min(a, b int) int {
11 | if a < b {
12 | return a
13 | }
14 | return b
15 | }
16 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/nodes.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | // The root document
4 | type nodeDocument struct {
5 | Nodes []INode
6 | }
7 |
8 | func (doc *nodeDocument) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
9 | for _, n := range doc.Nodes {
10 | err := n.Execute(ctx, writer)
11 | if err != nil {
12 | return err
13 | }
14 | }
15 | return nil
16 | }
17 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/nodes_html.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type nodeHTML struct {
4 | token *Token
5 | }
6 |
7 | func (n *nodeHTML) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
8 | writer.WriteString(n.token.Val)
9 | return nil
10 | }
11 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/nodes_wrapper.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type NodeWrapper struct {
4 | Endtag string
5 | nodes []INode
6 | }
7 |
8 | func (wrapper *NodeWrapper) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
9 | for _, n := range wrapper.nodes {
10 | err := n.Execute(ctx, writer)
11 | if err != nil {
12 | return err
13 | }
14 | }
15 | return nil
16 | }
17 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/parser_document.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | // Doc = { ( Filter | Tag | HTML ) }
4 | func (p *Parser) parseDocElement() (INode, *Error) {
5 | t := p.Current()
6 |
7 | switch t.Typ {
8 | case TokenHTML:
9 | p.Consume() // consume HTML element
10 | return &nodeHTML{token: t}, nil
11 | case TokenSymbol:
12 | switch t.Val {
13 | case "{{":
14 | // parse variable
15 | variable, err := p.parseVariableElement()
16 | if err != nil {
17 | return nil, err
18 | }
19 | return variable, nil
20 | case "{%":
21 | // parse tag
22 | tag, err := p.parseTagElement()
23 | if err != nil {
24 | return nil, err
25 | }
26 | return tag, nil
27 | }
28 | }
29 | return nil, p.Error("Unexpected token (only HTML/tags/filters in templates allowed)", t)
30 | }
31 |
32 | func (tpl *Template) parse() *Error {
33 | tpl.parser = newParser(tpl.name, tpl.tokens, tpl)
34 | doc, err := tpl.parser.parseDocument()
35 | if err != nil {
36 | return err
37 | }
38 | tpl.root = doc
39 | return nil
40 | }
41 |
42 | func (p *Parser) parseDocument() (*nodeDocument, *Error) {
43 | doc := &nodeDocument{}
44 |
45 | for p.Remaining() > 0 {
46 | node, err := p.parseDocElement()
47 | if err != nil {
48 | return nil, err
49 | }
50 | doc.Nodes = append(doc.Nodes, node)
51 | }
52 |
53 | return doc, nil
54 | }
55 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/pongo2.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | // Version string
4 | const Version = "dev"
5 |
6 | // Must panics, if a Template couldn't successfully parsed. This is how you
7 | // would use it:
8 | // var baseTemplate = pongo2.Must(pongo2.FromFile("templates/base.html"))
9 | func Must(tpl *Template, err error) *Template {
10 | if err != nil {
11 | panic(err)
12 | }
13 | return tpl
14 | }
15 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | /* Incomplete:
4 | -----------
5 |
6 | verbatim (only the "name" argument is missing for verbatim)
7 |
8 | Reconsideration:
9 | ----------------
10 |
11 | debug (reason: not sure what to output yet)
12 | regroup / Grouping on other properties (reason: maybe too python-specific; not sure how useful this would be in Go)
13 |
14 | Following built-in tags wont be added:
15 | --------------------------------------
16 |
17 | csrf_token (reason: web-framework specific)
18 | load (reason: python-specific)
19 | url (reason: web-framework specific)
20 | */
21 |
22 | import (
23 | "fmt"
24 | )
25 |
26 | type INodeTag interface {
27 | INode
28 | }
29 |
30 | // This is the function signature of the tag's parser you will have
31 | // to implement in order to create a new tag.
32 | //
33 | // 'doc' is providing access to the whole document while 'arguments'
34 | // is providing access to the user's arguments to the tag:
35 | //
36 | // {% your_tag_name some "arguments" 123 %}
37 | //
38 | // start_token will be the *Token with the tag's name in it (here: your_tag_name).
39 | //
40 | // Please see the Parser documentation on how to use the parser.
41 | // See RegisterTag()'s documentation for more information about
42 | // writing a tag as well.
43 | type TagParser func(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error)
44 |
45 | type tag struct {
46 | name string
47 | parser TagParser
48 | }
49 |
50 | var tags map[string]*tag
51 |
52 | func init() {
53 | tags = make(map[string]*tag)
54 | }
55 |
56 | // Registers a new tag. If there's already a tag with the same
57 | // name, RegisterTag will panic. You usually want to call this
58 | // function in the tag's init() function:
59 | // http://golang.org/doc/effective_go.html#init
60 | //
61 | // See http://www.florian-schlachter.de/post/pongo2/ for more about
62 | // writing filters and tags.
63 | func RegisterTag(name string, parserFn TagParser) {
64 | _, existing := tags[name]
65 | if existing {
66 | panic(fmt.Sprintf("Tag with name '%s' is already registered.", name))
67 | }
68 | tags[name] = &tag{
69 | name: name,
70 | parser: parserFn,
71 | }
72 | }
73 |
74 | // Replaces an already registered tag with a new implementation. Use this
75 | // function with caution since it allows you to change existing tag behaviour.
76 | func ReplaceTag(name string, parserFn TagParser) {
77 | _, existing := tags[name]
78 | if !existing {
79 | panic(fmt.Sprintf("Tag with name '%s' does not exist (therefore cannot be overridden).", name))
80 | }
81 | tags[name] = &tag{
82 | name: name,
83 | parser: parserFn,
84 | }
85 | }
86 |
87 | // Tag = "{%" IDENT ARGS "%}"
88 | func (p *Parser) parseTagElement() (INodeTag, *Error) {
89 | p.Consume() // consume "{%"
90 | tokenName := p.MatchType(TokenIdentifier)
91 |
92 | // Check for identifier
93 | if tokenName == nil {
94 | return nil, p.Error("Tag name must be an identifier.", nil)
95 | }
96 |
97 | // Check for the existing tag
98 | tag, exists := tags[tokenName.Val]
99 | if !exists {
100 | // Does not exists
101 | return nil, p.Error(fmt.Sprintf("Tag '%s' not found (or beginning tag not provided)", tokenName.Val), tokenName)
102 | }
103 |
104 | // Check sandbox tag restriction
105 | if _, isBanned := p.template.set.bannedTags[tokenName.Val]; isBanned {
106 | return nil, p.Error(fmt.Sprintf("Usage of tag '%s' is not allowed (sandbox restriction active).", tokenName.Val), tokenName)
107 | }
108 |
109 | var argsToken []*Token
110 | for p.Peek(TokenSymbol, "%}") == nil && p.Remaining() > 0 {
111 | // Add token to args
112 | argsToken = append(argsToken, p.Current())
113 | p.Consume() // next token
114 | }
115 |
116 | // EOF?
117 | if p.Remaining() == 0 {
118 | return nil, p.Error("Unexpectedly reached EOF, no tag end found.", p.lastToken)
119 | }
120 |
121 | p.Match(TokenSymbol, "%}")
122 |
123 | argParser := newParser(p.name, argsToken, p.template)
124 | if len(argsToken) == 0 {
125 | // This is done to have nice EOF error messages
126 | argParser.lastToken = tokenName
127 | }
128 |
129 | p.template.level++
130 | defer func() { p.template.level-- }()
131 | return tag.parser(p, tokenName, argParser)
132 | }
133 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_autoescape.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagAutoescapeNode struct {
4 | wrapper *NodeWrapper
5 | autoescape bool
6 | }
7 |
8 | func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
9 | old := ctx.Autoescape
10 | ctx.Autoescape = node.autoescape
11 |
12 | err := node.wrapper.Execute(ctx, writer)
13 | if err != nil {
14 | return err
15 | }
16 |
17 | ctx.Autoescape = old
18 |
19 | return nil
20 | }
21 |
22 | func tagAutoescapeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
23 | autoescapeNode := &tagAutoescapeNode{}
24 |
25 | wrapper, _, err := doc.WrapUntilTag("endautoescape")
26 | if err != nil {
27 | return nil, err
28 | }
29 | autoescapeNode.wrapper = wrapper
30 |
31 | modeToken := arguments.MatchType(TokenIdentifier)
32 | if modeToken == nil {
33 | return nil, arguments.Error("A mode is required for autoescape-tag.", nil)
34 | }
35 | if modeToken.Val == "on" {
36 | autoescapeNode.autoescape = true
37 | } else if modeToken.Val == "off" {
38 | autoescapeNode.autoescape = false
39 | } else {
40 | return nil, arguments.Error("Only 'on' or 'off' is valid as an autoescape-mode.", nil)
41 | }
42 |
43 | if arguments.Remaining() > 0 {
44 | return nil, arguments.Error("Malformed autoescape-tag arguments.", nil)
45 | }
46 |
47 | return autoescapeNode, nil
48 | }
49 |
50 | func init() {
51 | RegisterTag("autoescape", tagAutoescapeParser)
52 | }
53 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_block.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | type tagBlockNode struct {
8 | name string
9 | }
10 |
11 | func (node *tagBlockNode) getBlockWrapperByName(tpl *Template) *NodeWrapper {
12 | var t *NodeWrapper
13 | if tpl.child != nil {
14 | // First ask the child for the block
15 | t = node.getBlockWrapperByName(tpl.child)
16 | }
17 | if t == nil {
18 | // Child has no block, lets look up here at parent
19 | t = tpl.blocks[node.name]
20 | }
21 | return t
22 | }
23 |
24 | func (node *tagBlockNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
25 | tpl := ctx.template
26 | if tpl == nil {
27 | panic("internal error: tpl == nil")
28 | }
29 | // Determine the block to execute
30 | blockWrapper := node.getBlockWrapperByName(tpl)
31 | if blockWrapper == nil {
32 | // fmt.Printf("could not find: %s\n", node.name)
33 | return ctx.Error("internal error: block_wrapper == nil in tagBlockNode.Execute()", nil)
34 | }
35 | err := blockWrapper.Execute(ctx, writer)
36 | if err != nil {
37 | return err
38 | }
39 |
40 | // TODO: Add support for {{ block.super }}
41 |
42 | return nil
43 | }
44 |
45 | func tagBlockParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
46 | if arguments.Count() == 0 {
47 | return nil, arguments.Error("Tag 'block' requires an identifier.", nil)
48 | }
49 |
50 | nameToken := arguments.MatchType(TokenIdentifier)
51 | if nameToken == nil {
52 | return nil, arguments.Error("First argument for tag 'block' must be an identifier.", nil)
53 | }
54 |
55 | if arguments.Remaining() != 0 {
56 | return nil, arguments.Error("Tag 'block' takes exactly 1 argument (an identifier).", nil)
57 | }
58 |
59 | wrapper, endtagargs, err := doc.WrapUntilTag("endblock")
60 | if err != nil {
61 | return nil, err
62 | }
63 | if endtagargs.Remaining() > 0 {
64 | endtagnameToken := endtagargs.MatchType(TokenIdentifier)
65 | if endtagnameToken != nil {
66 | if endtagnameToken.Val != nameToken.Val {
67 | return nil, endtagargs.Error(fmt.Sprintf("Name for 'endblock' must equal to 'block'-tag's name ('%s' != '%s').",
68 | nameToken.Val, endtagnameToken.Val), nil)
69 | }
70 | }
71 |
72 | if endtagnameToken == nil || endtagargs.Remaining() > 0 {
73 | return nil, endtagargs.Error("Either no or only one argument (identifier) allowed for 'endblock'.", nil)
74 | }
75 | }
76 |
77 | tpl := doc.template
78 | if tpl == nil {
79 | panic("internal error: tpl == nil")
80 | }
81 | _, hasBlock := tpl.blocks[nameToken.Val]
82 | if !hasBlock {
83 | tpl.blocks[nameToken.Val] = wrapper
84 | } else {
85 | return nil, arguments.Error(fmt.Sprintf("Block named '%s' already defined", nameToken.Val), nil)
86 | }
87 |
88 | return &tagBlockNode{name: nameToken.Val}, nil
89 | }
90 |
91 | func init() {
92 | RegisterTag("block", tagBlockParser)
93 | }
94 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_comment.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagCommentNode struct{}
4 |
5 | func (node *tagCommentNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
6 | return nil
7 | }
8 |
9 | func tagCommentParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
10 | commentNode := &tagCommentNode{}
11 |
12 | // TODO: Process the endtag's arguments (see django 'comment'-tag documentation)
13 | _, _, err := doc.WrapUntilTag("endcomment")
14 | if err != nil {
15 | return nil, err
16 | }
17 |
18 | if arguments.Count() != 0 {
19 | return nil, arguments.Error("Tag 'comment' does not take any argument.", nil)
20 | }
21 |
22 | return commentNode, nil
23 | }
24 |
25 | func init() {
26 | RegisterTag("comment", tagCommentParser)
27 | }
28 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_cycle.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagCycleValue struct {
4 | node *tagCycleNode
5 | value *Value
6 | }
7 |
8 | type tagCycleNode struct {
9 | position *Token
10 | args []IEvaluator
11 | idx int
12 | asName string
13 | silent bool
14 | }
15 |
16 | func (cv *tagCycleValue) String() string {
17 | return cv.value.String()
18 | }
19 |
20 | func (node *tagCycleNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
21 | item := node.args[node.idx%len(node.args)]
22 | node.idx++
23 |
24 | val, err := item.Evaluate(ctx)
25 | if err != nil {
26 | return err
27 | }
28 |
29 | if t, ok := val.Interface().(*tagCycleValue); ok {
30 | // {% cycle "test1" "test2"
31 | // {% cycle cycleitem %}
32 |
33 | // Update the cycle value with next value
34 | item := t.node.args[t.node.idx%len(t.node.args)]
35 | t.node.idx++
36 |
37 | val, err := item.Evaluate(ctx)
38 | if err != nil {
39 | return err
40 | }
41 |
42 | t.value = val
43 |
44 | if !t.node.silent {
45 | writer.WriteString(val.String())
46 | }
47 | } else {
48 | // Regular call
49 |
50 | cycleValue := &tagCycleValue{
51 | node: node,
52 | value: val,
53 | }
54 |
55 | if node.asName != "" {
56 | ctx.Private[node.asName] = cycleValue
57 | }
58 | if !node.silent {
59 | writer.WriteString(val.String())
60 | }
61 | }
62 |
63 | return nil
64 | }
65 |
66 | // HINT: We're not supporting the old comma-seperated list of expresions argument-style
67 | func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
68 | cycleNode := &tagCycleNode{
69 | position: start,
70 | }
71 |
72 | for arguments.Remaining() > 0 {
73 | node, err := arguments.ParseExpression()
74 | if err != nil {
75 | return nil, err
76 | }
77 | cycleNode.args = append(cycleNode.args, node)
78 |
79 | if arguments.MatchOne(TokenKeyword, "as") != nil {
80 | // as
81 |
82 | nameToken := arguments.MatchType(TokenIdentifier)
83 | if nameToken == nil {
84 | return nil, arguments.Error("Name (identifier) expected after 'as'.", nil)
85 | }
86 | cycleNode.asName = nameToken.Val
87 |
88 | if arguments.MatchOne(TokenIdentifier, "silent") != nil {
89 | cycleNode.silent = true
90 | }
91 |
92 | // Now we're finished
93 | break
94 | }
95 | }
96 |
97 | if arguments.Remaining() > 0 {
98 | return nil, arguments.Error("Malformed cycle-tag.", nil)
99 | }
100 |
101 | return cycleNode, nil
102 | }
103 |
104 | func init() {
105 | RegisterTag("cycle", tagCycleParser)
106 | }
107 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_extends.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagExtendsNode struct {
4 | filename string
5 | }
6 |
7 | func (node *tagExtendsNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
8 | return nil
9 | }
10 |
11 | func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
12 | extendsNode := &tagExtendsNode{}
13 |
14 | if doc.template.level > 1 {
15 | return nil, arguments.Error("The 'extends' tag can only defined on root level.", start)
16 | }
17 |
18 | if doc.template.parent != nil {
19 | // Already one parent
20 | return nil, arguments.Error("This template has already one parent.", start)
21 | }
22 |
23 | if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
24 | // prepared, static template
25 |
26 | // Get parent's filename
27 | parentFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
28 |
29 | // Parse the parent
30 | parentTemplate, err := doc.template.set.FromFile(parentFilename)
31 | if err != nil {
32 | return nil, err.(*Error)
33 | }
34 |
35 | // Keep track of things
36 | parentTemplate.child = doc.template
37 | doc.template.parent = parentTemplate
38 | extendsNode.filename = parentFilename
39 | } else {
40 | return nil, arguments.Error("Tag 'extends' requires a template filename as string.", nil)
41 | }
42 |
43 | if arguments.Remaining() > 0 {
44 | return nil, arguments.Error("Tag 'extends' does only take 1 argument.", nil)
45 | }
46 |
47 | return extendsNode, nil
48 | }
49 |
50 | func init() {
51 | RegisterTag("extends", tagExtendsParser)
52 | }
53 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_filter.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "bytes"
5 | )
6 |
7 | type nodeFilterCall struct {
8 | name string
9 | paramExpr IEvaluator
10 | }
11 |
12 | type tagFilterNode struct {
13 | position *Token
14 | bodyWrapper *NodeWrapper
15 | filterChain []*nodeFilterCall
16 | }
17 |
18 | func (node *tagFilterNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
19 | temp := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB size
20 |
21 | err := node.bodyWrapper.Execute(ctx, temp)
22 | if err != nil {
23 | return err
24 | }
25 |
26 | value := AsValue(temp.String())
27 |
28 | for _, call := range node.filterChain {
29 | var param *Value
30 | if call.paramExpr != nil {
31 | param, err = call.paramExpr.Evaluate(ctx)
32 | if err != nil {
33 | return err
34 | }
35 | } else {
36 | param = AsValue(nil)
37 | }
38 | value, err = ApplyFilter(call.name, value, param)
39 | if err != nil {
40 | return ctx.Error(err.Error(), node.position)
41 | }
42 | }
43 |
44 | writer.WriteString(value.String())
45 |
46 | return nil
47 | }
48 |
49 | func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
50 | filterNode := &tagFilterNode{
51 | position: start,
52 | }
53 |
54 | wrapper, _, err := doc.WrapUntilTag("endfilter")
55 | if err != nil {
56 | return nil, err
57 | }
58 | filterNode.bodyWrapper = wrapper
59 |
60 | for arguments.Remaining() > 0 {
61 | filterCall := &nodeFilterCall{}
62 |
63 | nameToken := arguments.MatchType(TokenIdentifier)
64 | if nameToken == nil {
65 | return nil, arguments.Error("Expected a filter name (identifier).", nil)
66 | }
67 | filterCall.name = nameToken.Val
68 |
69 | if arguments.MatchOne(TokenSymbol, ":") != nil {
70 | // Filter parameter
71 | // NOTICE: we can't use ParseExpression() here, because it would parse the next filter "|..." as well in the argument list
72 | expr, err := arguments.parseVariableOrLiteral()
73 | if err != nil {
74 | return nil, err
75 | }
76 | filterCall.paramExpr = expr
77 | }
78 |
79 | filterNode.filterChain = append(filterNode.filterChain, filterCall)
80 |
81 | if arguments.MatchOne(TokenSymbol, "|") == nil {
82 | break
83 | }
84 | }
85 |
86 | if arguments.Remaining() > 0 {
87 | return nil, arguments.Error("Malformed filter-tag arguments.", nil)
88 | }
89 |
90 | return filterNode, nil
91 | }
92 |
93 | func init() {
94 | RegisterTag("filter", tagFilterParser)
95 | }
96 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_firstof.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagFirstofNode struct {
4 | position *Token
5 | args []IEvaluator
6 | }
7 |
8 | func (node *tagFirstofNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
9 | for _, arg := range node.args {
10 | val, err := arg.Evaluate(ctx)
11 | if err != nil {
12 | return err
13 | }
14 |
15 | if val.IsTrue() {
16 | if ctx.Autoescape && !arg.FilterApplied("safe") {
17 | val, err = ApplyFilter("escape", val, nil)
18 | if err != nil {
19 | return err
20 | }
21 | }
22 |
23 | writer.WriteString(val.String())
24 | return nil
25 | }
26 | }
27 |
28 | return nil
29 | }
30 |
31 | func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
32 | firstofNode := &tagFirstofNode{
33 | position: start,
34 | }
35 |
36 | for arguments.Remaining() > 0 {
37 | node, err := arguments.ParseExpression()
38 | if err != nil {
39 | return nil, err
40 | }
41 | firstofNode.args = append(firstofNode.args, node)
42 | }
43 |
44 | return firstofNode, nil
45 | }
46 |
47 | func init() {
48 | RegisterTag("firstof", tagFirstofParser)
49 | }
50 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_for.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagForNode struct {
4 | key string
5 | value string // only for maps: for key, value in map
6 | objectEvaluator IEvaluator
7 | reversed bool
8 | sorted bool
9 |
10 | bodyWrapper *NodeWrapper
11 | emptyWrapper *NodeWrapper
12 | }
13 |
14 | type tagForLoopInformation struct {
15 | Counter int
16 | Counter0 int
17 | Revcounter int
18 | Revcounter0 int
19 | First bool
20 | Last bool
21 | Parentloop *tagForLoopInformation
22 | }
23 |
24 | func (node *tagForNode) Execute(ctx *ExecutionContext, writer TemplateWriter) (forError *Error) {
25 | // Backup forloop (as parentloop in public context), key-name and value-name
26 | forCtx := NewChildExecutionContext(ctx)
27 | parentloop := forCtx.Private["forloop"]
28 |
29 | // Create loop struct
30 | loopInfo := &tagForLoopInformation{
31 | First: true,
32 | }
33 |
34 | // Is it a loop in a loop?
35 | if parentloop != nil {
36 | loopInfo.Parentloop = parentloop.(*tagForLoopInformation)
37 | }
38 |
39 | // Register loopInfo in public context
40 | forCtx.Private["forloop"] = loopInfo
41 |
42 | obj, err := node.objectEvaluator.Evaluate(forCtx)
43 | if err != nil {
44 | return err
45 | }
46 |
47 | obj.IterateOrder(func(idx, count int, key, value *Value) bool {
48 | // There's something to iterate over (correct type and at least 1 item)
49 |
50 | // Update loop infos and public context
51 | forCtx.Private[node.key] = key
52 | if value != nil {
53 | forCtx.Private[node.value] = value
54 | }
55 | loopInfo.Counter = idx + 1
56 | loopInfo.Counter0 = idx
57 | if idx == 1 {
58 | loopInfo.First = false
59 | }
60 | if idx+1 == count {
61 | loopInfo.Last = true
62 | }
63 | loopInfo.Revcounter = count - idx // TODO: Not sure about this, have to look it up
64 | loopInfo.Revcounter0 = count - (idx + 1) // TODO: Not sure about this, have to look it up
65 |
66 | // Render elements with updated context
67 | err := node.bodyWrapper.Execute(forCtx, writer)
68 | if err != nil {
69 | forError = err
70 | return false
71 | }
72 | return true
73 | }, func() {
74 | // Nothing to iterate over (maybe wrong type or no items)
75 | if node.emptyWrapper != nil {
76 | err := node.emptyWrapper.Execute(forCtx, writer)
77 | if err != nil {
78 | forError = err
79 | }
80 | }
81 | }, node.reversed, node.sorted)
82 |
83 | return forError
84 | }
85 |
86 | func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
87 | forNode := &tagForNode{}
88 |
89 | // Arguments parsing
90 | var valueToken *Token
91 | keyToken := arguments.MatchType(TokenIdentifier)
92 | if keyToken == nil {
93 | return nil, arguments.Error("Expected an key identifier as first argument for 'for'-tag", nil)
94 | }
95 |
96 | if arguments.Match(TokenSymbol, ",") != nil {
97 | // Value name is provided
98 | valueToken = arguments.MatchType(TokenIdentifier)
99 | if valueToken == nil {
100 | return nil, arguments.Error("Value name must be an identifier.", nil)
101 | }
102 | }
103 |
104 | if arguments.Match(TokenKeyword, "in") == nil {
105 | return nil, arguments.Error("Expected keyword 'in'.", nil)
106 | }
107 |
108 | objectEvaluator, err := arguments.ParseExpression()
109 | if err != nil {
110 | return nil, err
111 | }
112 | forNode.objectEvaluator = objectEvaluator
113 | forNode.key = keyToken.Val
114 | if valueToken != nil {
115 | forNode.value = valueToken.Val
116 | }
117 |
118 | if arguments.MatchOne(TokenIdentifier, "reversed") != nil {
119 | forNode.reversed = true
120 | }
121 |
122 | if arguments.MatchOne(TokenIdentifier, "sorted") != nil {
123 | forNode.sorted = true
124 | }
125 |
126 | if arguments.Remaining() > 0 {
127 | return nil, arguments.Error("Malformed for-loop arguments.", nil)
128 | }
129 |
130 | // Body wrapping
131 | wrapper, endargs, err := doc.WrapUntilTag("empty", "endfor")
132 | if err != nil {
133 | return nil, err
134 | }
135 | forNode.bodyWrapper = wrapper
136 |
137 | if endargs.Count() > 0 {
138 | return nil, endargs.Error("Arguments not allowed here.", nil)
139 | }
140 |
141 | if wrapper.Endtag == "empty" {
142 | // if there's an else in the if-statement, we need the else-Block as well
143 | wrapper, endargs, err = doc.WrapUntilTag("endfor")
144 | if err != nil {
145 | return nil, err
146 | }
147 | forNode.emptyWrapper = wrapper
148 |
149 | if endargs.Count() > 0 {
150 | return nil, endargs.Error("Arguments not allowed here.", nil)
151 | }
152 | }
153 |
154 | return forNode, nil
155 | }
156 |
157 | func init() {
158 | RegisterTag("for", tagForParser)
159 | }
160 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_if.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagIfNode struct {
4 | conditions []IEvaluator
5 | wrappers []*NodeWrapper
6 | }
7 |
8 | func (node *tagIfNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
9 | for i, condition := range node.conditions {
10 | result, err := condition.Evaluate(ctx)
11 | if err != nil {
12 | return err
13 | }
14 |
15 | if result.IsTrue() {
16 | return node.wrappers[i].Execute(ctx, writer)
17 | }
18 | // Last condition?
19 | if len(node.conditions) == i+1 && len(node.wrappers) > i+1 {
20 | return node.wrappers[i+1].Execute(ctx, writer)
21 | }
22 | }
23 | return nil
24 | }
25 |
26 | func tagIfParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
27 | ifNode := &tagIfNode{}
28 |
29 | // Parse first and main IF condition
30 | condition, err := arguments.ParseExpression()
31 | if err != nil {
32 | return nil, err
33 | }
34 | ifNode.conditions = append(ifNode.conditions, condition)
35 |
36 | if arguments.Remaining() > 0 {
37 | return nil, arguments.Error("If-condition is malformed.", nil)
38 | }
39 |
40 | // Check the rest
41 | for {
42 | wrapper, tagArgs, err := doc.WrapUntilTag("elif", "else", "endif")
43 | if err != nil {
44 | return nil, err
45 | }
46 | ifNode.wrappers = append(ifNode.wrappers, wrapper)
47 |
48 | if wrapper.Endtag == "elif" {
49 | // elif can take a condition
50 | condition, err = tagArgs.ParseExpression()
51 | if err != nil {
52 | return nil, err
53 | }
54 | ifNode.conditions = append(ifNode.conditions, condition)
55 |
56 | if tagArgs.Remaining() > 0 {
57 | return nil, tagArgs.Error("Elif-condition is malformed.", nil)
58 | }
59 | } else {
60 | if tagArgs.Count() > 0 {
61 | // else/endif can't take any conditions
62 | return nil, tagArgs.Error("Arguments not allowed here.", nil)
63 | }
64 | }
65 |
66 | if wrapper.Endtag == "endif" {
67 | break
68 | }
69 | }
70 |
71 | return ifNode, nil
72 | }
73 |
74 | func init() {
75 | RegisterTag("if", tagIfParser)
76 | }
77 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_ifchanged.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "bytes"
5 | )
6 |
7 | type tagIfchangedNode struct {
8 | watchedExpr []IEvaluator
9 | lastValues []*Value
10 | lastContent []byte
11 | thenWrapper *NodeWrapper
12 | elseWrapper *NodeWrapper
13 | }
14 |
15 | func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
16 | if len(node.watchedExpr) == 0 {
17 | // Check against own rendered body
18 |
19 | buf := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
20 | err := node.thenWrapper.Execute(ctx, buf)
21 | if err != nil {
22 | return err
23 | }
24 |
25 | bufBytes := buf.Bytes()
26 | if !bytes.Equal(node.lastContent, bufBytes) {
27 | // Rendered content changed, output it
28 | writer.Write(bufBytes)
29 | node.lastContent = bufBytes
30 | }
31 | } else {
32 | nowValues := make([]*Value, 0, len(node.watchedExpr))
33 | for _, expr := range node.watchedExpr {
34 | val, err := expr.Evaluate(ctx)
35 | if err != nil {
36 | return err
37 | }
38 | nowValues = append(nowValues, val)
39 | }
40 |
41 | // Compare old to new values now
42 | changed := len(node.lastValues) == 0
43 |
44 | for idx, oldVal := range node.lastValues {
45 | if !oldVal.EqualValueTo(nowValues[idx]) {
46 | changed = true
47 | break // we can stop here because ONE value changed
48 | }
49 | }
50 |
51 | node.lastValues = nowValues
52 |
53 | if changed {
54 | // Render thenWrapper
55 | err := node.thenWrapper.Execute(ctx, writer)
56 | if err != nil {
57 | return err
58 | }
59 | } else {
60 | // Render elseWrapper
61 | err := node.elseWrapper.Execute(ctx, writer)
62 | if err != nil {
63 | return err
64 | }
65 | }
66 | }
67 |
68 | return nil
69 | }
70 |
71 | func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
72 | ifchangedNode := &tagIfchangedNode{}
73 |
74 | for arguments.Remaining() > 0 {
75 | // Parse condition
76 | expr, err := arguments.ParseExpression()
77 | if err != nil {
78 | return nil, err
79 | }
80 | ifchangedNode.watchedExpr = append(ifchangedNode.watchedExpr, expr)
81 | }
82 |
83 | if arguments.Remaining() > 0 {
84 | return nil, arguments.Error("Ifchanged-arguments are malformed.", nil)
85 | }
86 |
87 | // Wrap then/else-blocks
88 | wrapper, endargs, err := doc.WrapUntilTag("else", "endifchanged")
89 | if err != nil {
90 | return nil, err
91 | }
92 | ifchangedNode.thenWrapper = wrapper
93 |
94 | if endargs.Count() > 0 {
95 | return nil, endargs.Error("Arguments not allowed here.", nil)
96 | }
97 |
98 | if wrapper.Endtag == "else" {
99 | // if there's an else in the if-statement, we need the else-Block as well
100 | wrapper, endargs, err = doc.WrapUntilTag("endifchanged")
101 | if err != nil {
102 | return nil, err
103 | }
104 | ifchangedNode.elseWrapper = wrapper
105 |
106 | if endargs.Count() > 0 {
107 | return nil, endargs.Error("Arguments not allowed here.", nil)
108 | }
109 | }
110 |
111 | return ifchangedNode, nil
112 | }
113 |
114 | func init() {
115 | RegisterTag("ifchanged", tagIfchangedParser)
116 | }
117 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_ifequal.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagIfEqualNode struct {
4 | var1, var2 IEvaluator
5 | thenWrapper *NodeWrapper
6 | elseWrapper *NodeWrapper
7 | }
8 |
9 | func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
10 | r1, err := node.var1.Evaluate(ctx)
11 | if err != nil {
12 | return err
13 | }
14 | r2, err := node.var2.Evaluate(ctx)
15 | if err != nil {
16 | return err
17 | }
18 |
19 | result := r1.EqualValueTo(r2)
20 |
21 | if result {
22 | return node.thenWrapper.Execute(ctx, writer)
23 | }
24 | if node.elseWrapper != nil {
25 | return node.elseWrapper.Execute(ctx, writer)
26 | }
27 | return nil
28 | }
29 |
30 | func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
31 | ifequalNode := &tagIfEqualNode{}
32 |
33 | // Parse two expressions
34 | var1, err := arguments.ParseExpression()
35 | if err != nil {
36 | return nil, err
37 | }
38 | var2, err := arguments.ParseExpression()
39 | if err != nil {
40 | return nil, err
41 | }
42 | ifequalNode.var1 = var1
43 | ifequalNode.var2 = var2
44 |
45 | if arguments.Remaining() > 0 {
46 | return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
47 | }
48 |
49 | // Wrap then/else-blocks
50 | wrapper, endargs, err := doc.WrapUntilTag("else", "endifequal")
51 | if err != nil {
52 | return nil, err
53 | }
54 | ifequalNode.thenWrapper = wrapper
55 |
56 | if endargs.Count() > 0 {
57 | return nil, endargs.Error("Arguments not allowed here.", nil)
58 | }
59 |
60 | if wrapper.Endtag == "else" {
61 | // if there's an else in the if-statement, we need the else-Block as well
62 | wrapper, endargs, err = doc.WrapUntilTag("endifequal")
63 | if err != nil {
64 | return nil, err
65 | }
66 | ifequalNode.elseWrapper = wrapper
67 |
68 | if endargs.Count() > 0 {
69 | return nil, endargs.Error("Arguments not allowed here.", nil)
70 | }
71 | }
72 |
73 | return ifequalNode, nil
74 | }
75 |
76 | func init() {
77 | RegisterTag("ifequal", tagIfEqualParser)
78 | }
79 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_ifnotequal.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagIfNotEqualNode struct {
4 | var1, var2 IEvaluator
5 | thenWrapper *NodeWrapper
6 | elseWrapper *NodeWrapper
7 | }
8 |
9 | func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
10 | r1, err := node.var1.Evaluate(ctx)
11 | if err != nil {
12 | return err
13 | }
14 | r2, err := node.var2.Evaluate(ctx)
15 | if err != nil {
16 | return err
17 | }
18 |
19 | result := !r1.EqualValueTo(r2)
20 |
21 | if result {
22 | return node.thenWrapper.Execute(ctx, writer)
23 | }
24 | if node.elseWrapper != nil {
25 | return node.elseWrapper.Execute(ctx, writer)
26 | }
27 | return nil
28 | }
29 |
30 | func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
31 | ifnotequalNode := &tagIfNotEqualNode{}
32 |
33 | // Parse two expressions
34 | var1, err := arguments.ParseExpression()
35 | if err != nil {
36 | return nil, err
37 | }
38 | var2, err := arguments.ParseExpression()
39 | if err != nil {
40 | return nil, err
41 | }
42 | ifnotequalNode.var1 = var1
43 | ifnotequalNode.var2 = var2
44 |
45 | if arguments.Remaining() > 0 {
46 | return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
47 | }
48 |
49 | // Wrap then/else-blocks
50 | wrapper, endargs, err := doc.WrapUntilTag("else", "endifnotequal")
51 | if err != nil {
52 | return nil, err
53 | }
54 | ifnotequalNode.thenWrapper = wrapper
55 |
56 | if endargs.Count() > 0 {
57 | return nil, endargs.Error("Arguments not allowed here.", nil)
58 | }
59 |
60 | if wrapper.Endtag == "else" {
61 | // if there's an else in the if-statement, we need the else-Block as well
62 | wrapper, endargs, err = doc.WrapUntilTag("endifnotequal")
63 | if err != nil {
64 | return nil, err
65 | }
66 | ifnotequalNode.elseWrapper = wrapper
67 |
68 | if endargs.Count() > 0 {
69 | return nil, endargs.Error("Arguments not allowed here.", nil)
70 | }
71 | }
72 |
73 | return ifnotequalNode, nil
74 | }
75 |
76 | func init() {
77 | RegisterTag("ifnotequal", tagIfNotEqualParser)
78 | }
79 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_import.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | type tagImportNode struct {
8 | position *Token
9 | filename string
10 | macros map[string]*tagMacroNode // alias/name -> macro instance
11 | }
12 |
13 | func (node *tagImportNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
14 | for name, macro := range node.macros {
15 | func(name string, macro *tagMacroNode) {
16 | ctx.Private[name] = func(args ...*Value) *Value {
17 | return macro.call(ctx, args...)
18 | }
19 | }(name, macro)
20 | }
21 | return nil
22 | }
23 |
24 | func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
25 | importNode := &tagImportNode{
26 | position: start,
27 | macros: make(map[string]*tagMacroNode),
28 | }
29 |
30 | filenameToken := arguments.MatchType(TokenString)
31 | if filenameToken == nil {
32 | return nil, arguments.Error("Import-tag needs a filename as string.", nil)
33 | }
34 |
35 | importNode.filename = doc.template.set.resolveFilename(doc.template, filenameToken.Val)
36 |
37 | if arguments.Remaining() == 0 {
38 | return nil, arguments.Error("You must at least specify one macro to import.", nil)
39 | }
40 |
41 | // Compile the given template
42 | tpl, err := doc.template.set.FromFile(importNode.filename)
43 | if err != nil {
44 | return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, start)
45 | }
46 |
47 | for arguments.Remaining() > 0 {
48 | macroNameToken := arguments.MatchType(TokenIdentifier)
49 | if macroNameToken == nil {
50 | return nil, arguments.Error("Expected macro name (identifier).", nil)
51 | }
52 |
53 | asName := macroNameToken.Val
54 | if arguments.Match(TokenKeyword, "as") != nil {
55 | aliasToken := arguments.MatchType(TokenIdentifier)
56 | if aliasToken == nil {
57 | return nil, arguments.Error("Expected macro alias name (identifier).", nil)
58 | }
59 | asName = aliasToken.Val
60 | }
61 |
62 | macroInstance, has := tpl.exportedMacros[macroNameToken.Val]
63 | if !has {
64 | return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macroNameToken.Val,
65 | importNode.filename), macroNameToken)
66 | }
67 |
68 | importNode.macros[asName] = macroInstance
69 |
70 | if arguments.Remaining() == 0 {
71 | break
72 | }
73 |
74 | if arguments.Match(TokenSymbol, ",") == nil {
75 | return nil, arguments.Error("Expected ','.", nil)
76 | }
77 | }
78 |
79 | return importNode, nil
80 | }
81 |
82 | func init() {
83 | RegisterTag("import", tagImportParser)
84 | }
85 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_include.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagIncludeNode struct {
4 | tpl *Template
5 | filenameEvaluator IEvaluator
6 | lazy bool
7 | only bool
8 | filename string
9 | withPairs map[string]IEvaluator
10 | ifExists bool
11 | }
12 |
13 | func (node *tagIncludeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
14 | // Building the context for the template
15 | includeCtx := make(Context)
16 |
17 | // Fill the context with all data from the parent
18 | if !node.only {
19 | includeCtx.Update(ctx.Public)
20 | includeCtx.Update(ctx.Private)
21 | }
22 |
23 | // Put all custom with-pairs into the context
24 | for key, value := range node.withPairs {
25 | val, err := value.Evaluate(ctx)
26 | if err != nil {
27 | return err
28 | }
29 | includeCtx[key] = val
30 | }
31 |
32 | // Execute the template
33 | if node.lazy {
34 | // Evaluate the filename
35 | filename, err := node.filenameEvaluator.Evaluate(ctx)
36 | if err != nil {
37 | return err
38 | }
39 |
40 | if filename.String() == "" {
41 | return ctx.Error("Filename for 'include'-tag evaluated to an empty string.", nil)
42 | }
43 |
44 | // Get include-filename
45 | includedFilename := ctx.template.set.resolveFilename(ctx.template, filename.String())
46 |
47 | includedTpl, err2 := ctx.template.set.FromFile(includedFilename)
48 | if err2 != nil {
49 | // if this is ReadFile error, and "if_exists" flag is enabled
50 | if node.ifExists && err2.(*Error).Sender == "fromfile" {
51 | return nil
52 | }
53 | return err2.(*Error)
54 | }
55 | err2 = includedTpl.ExecuteWriter(includeCtx, writer)
56 | if err2 != nil {
57 | return err2.(*Error)
58 | }
59 | return nil
60 | }
61 | // Template is already parsed with static filename
62 | err := node.tpl.ExecuteWriter(includeCtx, writer)
63 | if err != nil {
64 | return err.(*Error)
65 | }
66 | return nil
67 | }
68 |
69 | type tagIncludeEmptyNode struct{}
70 |
71 | func (node *tagIncludeEmptyNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
72 | return nil
73 | }
74 |
75 | func tagIncludeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
76 | includeNode := &tagIncludeNode{
77 | withPairs: make(map[string]IEvaluator),
78 | }
79 |
80 | if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
81 | // prepared, static template
82 |
83 | // "if_exists" flag
84 | ifExists := arguments.Match(TokenIdentifier, "if_exists") != nil
85 |
86 | // Get include-filename
87 | includedFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
88 |
89 | // Parse the parent
90 | includeNode.filename = includedFilename
91 | includedTpl, err := doc.template.set.FromFile(includedFilename)
92 | if err != nil {
93 | // if this is ReadFile error, and "if_exists" token presents we should create and empty node
94 | if err.(*Error).Sender == "fromfile" && ifExists {
95 | return &tagIncludeEmptyNode{}, nil
96 | }
97 | return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, filenameToken)
98 | }
99 | includeNode.tpl = includedTpl
100 | } else {
101 | // No String, then the user wants to use lazy-evaluation (slower, but possible)
102 | filenameEvaluator, err := arguments.ParseExpression()
103 | if err != nil {
104 | return nil, err.updateFromTokenIfNeeded(doc.template, filenameToken)
105 | }
106 | includeNode.filenameEvaluator = filenameEvaluator
107 | includeNode.lazy = true
108 | includeNode.ifExists = arguments.Match(TokenIdentifier, "if_exists") != nil // "if_exists" flag
109 | }
110 |
111 | // After having parsed the filename we're gonna parse the with+only options
112 | if arguments.Match(TokenIdentifier, "with") != nil {
113 | for arguments.Remaining() > 0 {
114 | // We have at least one key=expr pair (because of starting "with")
115 | keyToken := arguments.MatchType(TokenIdentifier)
116 | if keyToken == nil {
117 | return nil, arguments.Error("Expected an identifier", nil)
118 | }
119 | if arguments.Match(TokenSymbol, "=") == nil {
120 | return nil, arguments.Error("Expected '='.", nil)
121 | }
122 | valueExpr, err := arguments.ParseExpression()
123 | if err != nil {
124 | return nil, err.updateFromTokenIfNeeded(doc.template, keyToken)
125 | }
126 |
127 | includeNode.withPairs[keyToken.Val] = valueExpr
128 |
129 | // Only?
130 | if arguments.Match(TokenIdentifier, "only") != nil {
131 | includeNode.only = true
132 | break // stop parsing arguments because it's the last option
133 | }
134 | }
135 | }
136 |
137 | if arguments.Remaining() > 0 {
138 | return nil, arguments.Error("Malformed 'include'-tag arguments.", nil)
139 | }
140 |
141 | return includeNode, nil
142 | }
143 |
144 | func init() {
145 | RegisterTag("include", tagIncludeParser)
146 | }
147 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_macro.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | )
7 |
8 | type tagMacroNode struct {
9 | position *Token
10 | name string
11 | argsOrder []string
12 | args map[string]IEvaluator
13 | exported bool
14 |
15 | wrapper *NodeWrapper
16 | }
17 |
18 | func (node *tagMacroNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
19 | ctx.Private[node.name] = func(args ...*Value) *Value {
20 | return node.call(ctx, args...)
21 | }
22 |
23 | return nil
24 | }
25 |
26 | func (node *tagMacroNode) call(ctx *ExecutionContext, args ...*Value) *Value {
27 | argsCtx := make(Context)
28 |
29 | for k, v := range node.args {
30 | if v == nil {
31 | // User did not provided a default value
32 | argsCtx[k] = nil
33 | } else {
34 | // Evaluate the default value
35 | valueExpr, err := v.Evaluate(ctx)
36 | if err != nil {
37 | ctx.Logf(err.Error())
38 | return AsSafeValue(err.Error())
39 | }
40 |
41 | argsCtx[k] = valueExpr
42 | }
43 | }
44 |
45 | if len(args) > len(node.argsOrder) {
46 | // Too many arguments, we're ignoring them and just logging into debug mode.
47 | err := ctx.Error(fmt.Sprintf("Macro '%s' called with too many arguments (%d instead of %d).",
48 | node.name, len(args), len(node.argsOrder)), nil).updateFromTokenIfNeeded(ctx.template, node.position)
49 |
50 | ctx.Logf(err.Error()) // TODO: This is a workaround, because the error is not returned yet to the Execution()-methods
51 | return AsSafeValue(err.Error())
52 | }
53 |
54 | // Make a context for the macro execution
55 | macroCtx := NewChildExecutionContext(ctx)
56 |
57 | // Register all arguments in the private context
58 | macroCtx.Private.Update(argsCtx)
59 |
60 | for idx, argValue := range args {
61 | macroCtx.Private[node.argsOrder[idx]] = argValue.Interface()
62 | }
63 |
64 | var b bytes.Buffer
65 | err := node.wrapper.Execute(macroCtx, &b)
66 | if err != nil {
67 | return AsSafeValue(err.updateFromTokenIfNeeded(ctx.template, node.position).Error())
68 | }
69 |
70 | return AsSafeValue(b.String())
71 | }
72 |
73 | func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
74 | macroNode := &tagMacroNode{
75 | position: start,
76 | args: make(map[string]IEvaluator),
77 | }
78 |
79 | nameToken := arguments.MatchType(TokenIdentifier)
80 | if nameToken == nil {
81 | return nil, arguments.Error("Macro-tag needs at least an identifier as name.", nil)
82 | }
83 | macroNode.name = nameToken.Val
84 |
85 | if arguments.MatchOne(TokenSymbol, "(") == nil {
86 | return nil, arguments.Error("Expected '('.", nil)
87 | }
88 |
89 | for arguments.Match(TokenSymbol, ")") == nil {
90 | argNameToken := arguments.MatchType(TokenIdentifier)
91 | if argNameToken == nil {
92 | return nil, arguments.Error("Expected argument name as identifier.", nil)
93 | }
94 | macroNode.argsOrder = append(macroNode.argsOrder, argNameToken.Val)
95 |
96 | if arguments.Match(TokenSymbol, "=") != nil {
97 | // Default expression follows
98 | argDefaultExpr, err := arguments.ParseExpression()
99 | if err != nil {
100 | return nil, err
101 | }
102 | macroNode.args[argNameToken.Val] = argDefaultExpr
103 | } else {
104 | // No default expression
105 | macroNode.args[argNameToken.Val] = nil
106 | }
107 |
108 | if arguments.Match(TokenSymbol, ")") != nil {
109 | break
110 | }
111 | if arguments.Match(TokenSymbol, ",") == nil {
112 | return nil, arguments.Error("Expected ',' or ')'.", nil)
113 | }
114 | }
115 |
116 | if arguments.Match(TokenKeyword, "export") != nil {
117 | macroNode.exported = true
118 | }
119 |
120 | if arguments.Remaining() > 0 {
121 | return nil, arguments.Error("Malformed macro-tag.", nil)
122 | }
123 |
124 | // Body wrapping
125 | wrapper, endargs, err := doc.WrapUntilTag("endmacro")
126 | if err != nil {
127 | return nil, err
128 | }
129 | macroNode.wrapper = wrapper
130 |
131 | if endargs.Count() > 0 {
132 | return nil, endargs.Error("Arguments not allowed here.", nil)
133 | }
134 |
135 | if macroNode.exported {
136 | // Now register the macro if it wants to be exported
137 | _, has := doc.template.exportedMacros[macroNode.name]
138 | if has {
139 | return nil, doc.Error(fmt.Sprintf("Another macro with name '%s' already exported.", macroNode.name), start)
140 | }
141 | doc.template.exportedMacros[macroNode.name] = macroNode
142 | }
143 |
144 | return macroNode, nil
145 | }
146 |
147 | func init() {
148 | RegisterTag("macro", tagMacroParser)
149 | }
150 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_now.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type tagNowNode struct {
8 | position *Token
9 | format string
10 | fake bool
11 | }
12 |
13 | func (node *tagNowNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
14 | var t time.Time
15 | if node.fake {
16 | t = time.Date(2014, time.February, 05, 18, 31, 45, 00, time.UTC)
17 | } else {
18 | t = time.Now()
19 | }
20 |
21 | writer.WriteString(t.Format(node.format))
22 |
23 | return nil
24 | }
25 |
26 | func tagNowParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
27 | nowNode := &tagNowNode{
28 | position: start,
29 | }
30 |
31 | formatToken := arguments.MatchType(TokenString)
32 | if formatToken == nil {
33 | return nil, arguments.Error("Expected a format string.", nil)
34 | }
35 | nowNode.format = formatToken.Val
36 |
37 | if arguments.MatchOne(TokenIdentifier, "fake") != nil {
38 | nowNode.fake = true
39 | }
40 |
41 | if arguments.Remaining() > 0 {
42 | return nil, arguments.Error("Malformed now-tag arguments.", nil)
43 | }
44 |
45 | return nowNode, nil
46 | }
47 |
48 | func init() {
49 | RegisterTag("now", tagNowParser)
50 | }
51 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_set.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagSetNode struct {
4 | name string
5 | expression IEvaluator
6 | }
7 |
8 | func (node *tagSetNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
9 | // Evaluate expression
10 | value, err := node.expression.Evaluate(ctx)
11 | if err != nil {
12 | return err
13 | }
14 |
15 | ctx.Private[node.name] = value
16 | return nil
17 | }
18 |
19 | func tagSetParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
20 | node := &tagSetNode{}
21 |
22 | // Parse variable name
23 | typeToken := arguments.MatchType(TokenIdentifier)
24 | if typeToken == nil {
25 | return nil, arguments.Error("Expected an identifier.", nil)
26 | }
27 | node.name = typeToken.Val
28 |
29 | if arguments.Match(TokenSymbol, "=") == nil {
30 | return nil, arguments.Error("Expected '='.", nil)
31 | }
32 |
33 | // Variable expression
34 | keyExpression, err := arguments.ParseExpression()
35 | if err != nil {
36 | return nil, err
37 | }
38 | node.expression = keyExpression
39 |
40 | // Remaining arguments
41 | if arguments.Remaining() > 0 {
42 | return nil, arguments.Error("Malformed 'set'-tag arguments.", nil)
43 | }
44 |
45 | return node, nil
46 | }
47 |
48 | func init() {
49 | RegisterTag("set", tagSetParser)
50 | }
51 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_spaceless.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "bytes"
5 | "regexp"
6 | )
7 |
8 | type tagSpacelessNode struct {
9 | wrapper *NodeWrapper
10 | }
11 |
12 | var tagSpacelessRegexp = regexp.MustCompile(`(?U:(<.*>))([\t\n\v\f\r ]+)(?U:(<.*>))`)
13 |
14 | func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
15 | b := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
16 |
17 | err := node.wrapper.Execute(ctx, b)
18 | if err != nil {
19 | return err
20 | }
21 |
22 | s := b.String()
23 | // Repeat this recursively
24 | changed := true
25 | for changed {
26 | s2 := tagSpacelessRegexp.ReplaceAllString(s, "$1$3")
27 | changed = s != s2
28 | s = s2
29 | }
30 |
31 | writer.WriteString(s)
32 |
33 | return nil
34 | }
35 |
36 | func tagSpacelessParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
37 | spacelessNode := &tagSpacelessNode{}
38 |
39 | wrapper, _, err := doc.WrapUntilTag("endspaceless")
40 | if err != nil {
41 | return nil, err
42 | }
43 | spacelessNode.wrapper = wrapper
44 |
45 | if arguments.Remaining() > 0 {
46 | return nil, arguments.Error("Malformed spaceless-tag arguments.", nil)
47 | }
48 |
49 | return spacelessNode, nil
50 | }
51 |
52 | func init() {
53 | RegisterTag("spaceless", tagSpacelessParser)
54 | }
55 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_ssi.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "io/ioutil"
5 | )
6 |
7 | type tagSSINode struct {
8 | filename string
9 | content string
10 | template *Template
11 | }
12 |
13 | func (node *tagSSINode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
14 | if node.template != nil {
15 | // Execute the template within the current context
16 | includeCtx := make(Context)
17 | includeCtx.Update(ctx.Public)
18 | includeCtx.Update(ctx.Private)
19 |
20 | err := node.template.execute(includeCtx, writer)
21 | if err != nil {
22 | return err.(*Error)
23 | }
24 | } else {
25 | // Just print out the content
26 | writer.WriteString(node.content)
27 | }
28 | return nil
29 | }
30 |
31 | func tagSSIParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
32 | SSINode := &tagSSINode{}
33 |
34 | if fileToken := arguments.MatchType(TokenString); fileToken != nil {
35 | SSINode.filename = fileToken.Val
36 |
37 | if arguments.Match(TokenIdentifier, "parsed") != nil {
38 | // parsed
39 | temporaryTpl, err := doc.template.set.FromFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
40 | if err != nil {
41 | return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, fileToken)
42 | }
43 | SSINode.template = temporaryTpl
44 | } else {
45 | // plaintext
46 | buf, err := ioutil.ReadFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
47 | if err != nil {
48 | return nil, (&Error{
49 | Sender: "tag:ssi",
50 | ErrorMsg: err.Error(),
51 | }).updateFromTokenIfNeeded(doc.template, fileToken)
52 | }
53 | SSINode.content = string(buf)
54 | }
55 | } else {
56 | return nil, arguments.Error("First argument must be a string.", nil)
57 | }
58 |
59 | if arguments.Remaining() > 0 {
60 | return nil, arguments.Error("Malformed SSI-tag argument.", nil)
61 | }
62 |
63 | return SSINode, nil
64 | }
65 |
66 | func init() {
67 | RegisterTag("ssi", tagSSIParser)
68 | }
69 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_templatetag.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagTemplateTagNode struct {
4 | content string
5 | }
6 |
7 | var templateTagMapping = map[string]string{
8 | "openblock": "{%",
9 | "closeblock": "%}",
10 | "openvariable": "{{",
11 | "closevariable": "}}",
12 | "openbrace": "{",
13 | "closebrace": "}",
14 | "opencomment": "{#",
15 | "closecomment": "#}",
16 | }
17 |
18 | func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
19 | writer.WriteString(node.content)
20 | return nil
21 | }
22 |
23 | func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
24 | ttNode := &tagTemplateTagNode{}
25 |
26 | if argToken := arguments.MatchType(TokenIdentifier); argToken != nil {
27 | output, found := templateTagMapping[argToken.Val]
28 | if !found {
29 | return nil, arguments.Error("Argument not found", argToken)
30 | }
31 | ttNode.content = output
32 | } else {
33 | return nil, arguments.Error("Identifier expected.", nil)
34 | }
35 |
36 | if arguments.Remaining() > 0 {
37 | return nil, arguments.Error("Malformed templatetag-tag argument.", nil)
38 | }
39 |
40 | return ttNode, nil
41 | }
42 |
43 | func init() {
44 | RegisterTag("templatetag", tagTemplateTagParser)
45 | }
46 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_widthratio.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "fmt"
5 | "math"
6 | )
7 |
8 | type tagWidthratioNode struct {
9 | position *Token
10 | current, max IEvaluator
11 | width IEvaluator
12 | ctxName string
13 | }
14 |
15 | func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
16 | current, err := node.current.Evaluate(ctx)
17 | if err != nil {
18 | return err
19 | }
20 |
21 | max, err := node.max.Evaluate(ctx)
22 | if err != nil {
23 | return err
24 | }
25 |
26 | width, err := node.width.Evaluate(ctx)
27 | if err != nil {
28 | return err
29 | }
30 |
31 | value := int(math.Ceil(current.Float()/max.Float()*width.Float() + 0.5))
32 |
33 | if node.ctxName == "" {
34 | writer.WriteString(fmt.Sprintf("%d", value))
35 | } else {
36 | ctx.Private[node.ctxName] = value
37 | }
38 |
39 | return nil
40 | }
41 |
42 | func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
43 | widthratioNode := &tagWidthratioNode{
44 | position: start,
45 | }
46 |
47 | current, err := arguments.ParseExpression()
48 | if err != nil {
49 | return nil, err
50 | }
51 | widthratioNode.current = current
52 |
53 | max, err := arguments.ParseExpression()
54 | if err != nil {
55 | return nil, err
56 | }
57 | widthratioNode.max = max
58 |
59 | width, err := arguments.ParseExpression()
60 | if err != nil {
61 | return nil, err
62 | }
63 | widthratioNode.width = width
64 |
65 | if arguments.MatchOne(TokenKeyword, "as") != nil {
66 | // Name follows
67 | nameToken := arguments.MatchType(TokenIdentifier)
68 | if nameToken == nil {
69 | return nil, arguments.Error("Expected name (identifier).", nil)
70 | }
71 | widthratioNode.ctxName = nameToken.Val
72 | }
73 |
74 | if arguments.Remaining() > 0 {
75 | return nil, arguments.Error("Malformed widthratio-tag arguments.", nil)
76 | }
77 |
78 | return widthratioNode, nil
79 | }
80 |
81 | func init() {
82 | RegisterTag("widthratio", tagWidthratioParser)
83 | }
84 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/tags_with.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | type tagWithNode struct {
4 | withPairs map[string]IEvaluator
5 | wrapper *NodeWrapper
6 | }
7 |
8 | func (node *tagWithNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
9 | //new context for block
10 | withctx := NewChildExecutionContext(ctx)
11 |
12 | // Put all custom with-pairs into the context
13 | for key, value := range node.withPairs {
14 | val, err := value.Evaluate(ctx)
15 | if err != nil {
16 | return err
17 | }
18 | withctx.Private[key] = val
19 | }
20 |
21 | return node.wrapper.Execute(withctx, writer)
22 | }
23 |
24 | func tagWithParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
25 | withNode := &tagWithNode{
26 | withPairs: make(map[string]IEvaluator),
27 | }
28 |
29 | if arguments.Count() == 0 {
30 | return nil, arguments.Error("Tag 'with' requires at least one argument.", nil)
31 | }
32 |
33 | wrapper, endargs, err := doc.WrapUntilTag("endwith")
34 | if err != nil {
35 | return nil, err
36 | }
37 | withNode.wrapper = wrapper
38 |
39 | if endargs.Count() > 0 {
40 | return nil, endargs.Error("Arguments not allowed here.", nil)
41 | }
42 |
43 | // Scan through all arguments to see which style the user uses (old or new style).
44 | // If we find any "as" keyword we will enforce old style; otherwise we will use new style.
45 | oldStyle := false // by default we're using the new_style
46 | for i := 0; i < arguments.Count(); i++ {
47 | if arguments.PeekN(i, TokenKeyword, "as") != nil {
48 | oldStyle = true
49 | break
50 | }
51 | }
52 |
53 | for arguments.Remaining() > 0 {
54 | if oldStyle {
55 | valueExpr, err := arguments.ParseExpression()
56 | if err != nil {
57 | return nil, err
58 | }
59 | if arguments.Match(TokenKeyword, "as") == nil {
60 | return nil, arguments.Error("Expected 'as' keyword.", nil)
61 | }
62 | keyToken := arguments.MatchType(TokenIdentifier)
63 | if keyToken == nil {
64 | return nil, arguments.Error("Expected an identifier", nil)
65 | }
66 | withNode.withPairs[keyToken.Val] = valueExpr
67 | } else {
68 | keyToken := arguments.MatchType(TokenIdentifier)
69 | if keyToken == nil {
70 | return nil, arguments.Error("Expected an identifier", nil)
71 | }
72 | if arguments.Match(TokenSymbol, "=") == nil {
73 | return nil, arguments.Error("Expected '='.", nil)
74 | }
75 | valueExpr, err := arguments.ParseExpression()
76 | if err != nil {
77 | return nil, err
78 | }
79 | withNode.withPairs[keyToken.Val] = valueExpr
80 | }
81 | }
82 |
83 | return withNode, nil
84 | }
85 |
86 | func init() {
87 | RegisterTag("with", tagWithParser)
88 | }
89 |
--------------------------------------------------------------------------------
/vendor/github.com/flosch/pongo2/template_loader.go:
--------------------------------------------------------------------------------
1 | package pongo2
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "io"
7 | "io/ioutil"
8 | "log"
9 | "os"
10 | "path/filepath"
11 | )
12 |
13 | // LocalFilesystemLoader represents a local filesystem loader with basic
14 | // BaseDirectory capabilities. The access to the local filesystem is unrestricted.
15 | type LocalFilesystemLoader struct {
16 | baseDir string
17 | }
18 |
19 | // MustNewLocalFileSystemLoader creates a new LocalFilesystemLoader instance
20 | // and panics if there's any error during instantiation. The parameters
21 | // are the same like NewLocalFileSystemLoader.
22 | func MustNewLocalFileSystemLoader(baseDir string) *LocalFilesystemLoader {
23 | fs, err := NewLocalFileSystemLoader(baseDir)
24 | if err != nil {
25 | log.Panic(err)
26 | }
27 | return fs
28 | }
29 |
30 | // NewLocalFileSystemLoader creates a new LocalFilesystemLoader and allows
31 | // templatesto be loaded from disk (unrestricted). If any base directory
32 | // is given (or being set using SetBaseDir), this base directory is being used
33 | // for path calculation in template inclusions/imports. Otherwise the path
34 | // is calculated based relatively to the including template's path.
35 | func NewLocalFileSystemLoader(baseDir string) (*LocalFilesystemLoader, error) {
36 | fs := &LocalFilesystemLoader{}
37 | if baseDir != "" {
38 | if err := fs.SetBaseDir(baseDir); err != nil {
39 | return nil, err
40 | }
41 | }
42 | return fs, nil
43 | }
44 |
45 | // SetBaseDir sets the template's base directory. This directory will
46 | // be used for any relative path in filters, tags and From*-functions to determine
47 | // your template. See the comment for NewLocalFileSystemLoader as well.
48 | func (fs *LocalFilesystemLoader) SetBaseDir(path string) error {
49 | // Make the path absolute
50 | if !filepath.IsAbs(path) {
51 | abs, err := filepath.Abs(path)
52 | if err != nil {
53 | return err
54 | }
55 | path = abs
56 | }
57 |
58 | // Check for existence
59 | fi, err := os.Stat(path)
60 | if err != nil {
61 | return err
62 | }
63 | if !fi.IsDir() {
64 | return fmt.Errorf("The given path '%s' is not a directory.", path)
65 | }
66 |
67 | fs.baseDir = path
68 | return nil
69 | }
70 |
71 | // Get reads the path's content from your local filesystem.
72 | func (fs *LocalFilesystemLoader) Get(path string) (io.Reader, error) {
73 | buf, err := ioutil.ReadFile(path)
74 | if err != nil {
75 | return nil, err
76 | }
77 | return bytes.NewReader(buf), nil
78 | }
79 |
80 | // Abs resolves a filename relative to the base directory. Absolute paths are allowed.
81 | // When there's no base dir set, the absolute path to the filename
82 | // will be calculated based on either the provided base directory (which
83 | // might be a path of a template which includes another template) or
84 | // the current working directory.
85 | func (fs *LocalFilesystemLoader) Abs(base, name string) string {
86 | if filepath.IsAbs(name) {
87 | return name
88 | }
89 |
90 | // Our own base dir has always priority; if there's none
91 | // we use the path provided in base.
92 | var err error
93 | if fs.baseDir == "" {
94 | if base == "" {
95 | base, err = os.Getwd()
96 | if err != nil {
97 | panic(err)
98 | }
99 | return filepath.Join(base, name)
100 | }
101 |
102 | return filepath.Join(filepath.Dir(base), name)
103 | }
104 |
105 | return filepath.Join(fs.baseDir, name)
106 | }
107 |
108 | // SandboxedFilesystemLoader is still WIP.
109 | type SandboxedFilesystemLoader struct {
110 | *LocalFilesystemLoader
111 | }
112 |
113 | // NewSandboxedFilesystemLoader creates a new sandboxed local file system instance.
114 | func NewSandboxedFilesystemLoader(baseDir string) (*SandboxedFilesystemLoader, error) {
115 | fs, err := NewLocalFileSystemLoader(baseDir)
116 | if err != nil {
117 | return nil, err
118 | }
119 | return &SandboxedFilesystemLoader{
120 | LocalFilesystemLoader: fs,
121 | }, nil
122 | }
123 |
124 | // Move sandbox to a virtual fs
125 |
126 | /*
127 | if len(set.SandboxDirectories) > 0 {
128 | defer func() {
129 | // Remove any ".." or other crap
130 | resolvedPath = filepath.Clean(resolvedPath)
131 |
132 | // Make the path absolute
133 | absPath, err := filepath.Abs(resolvedPath)
134 | if err != nil {
135 | panic(err)
136 | }
137 | resolvedPath = absPath
138 |
139 | // Check against the sandbox directories (once one pattern matches, we're done and can allow it)
140 | for _, pattern := range set.SandboxDirectories {
141 | matched, err := filepath.Match(pattern, resolvedPath)
142 | if err != nil {
143 | panic("Wrong sandbox directory match pattern (see http://golang.org/pkg/path/filepath/#Match).")
144 | }
145 | if matched {
146 | // OK!
147 | return
148 | }
149 | }
150 |
151 | // No pattern matched, we have to log+deny the request
152 | set.logf("Access attempt outside of the sandbox directories (blocked): '%s'", resolvedPath)
153 | resolvedPath = ""
154 | }()
155 | }
156 | */
157 |
--------------------------------------------------------------------------------
/vendor/github.com/juju/errors/Makefile:
--------------------------------------------------------------------------------
1 | default: check
2 |
3 | check:
4 | go test && go test -compiler gccgo
5 |
6 | docs:
7 | godoc2md github.com/juju/errors > README.md
8 | sed -i 's|\[godoc-link-here\]|[](https://godoc.org/github.com/juju/errors)|' README.md
9 |
10 |
11 | .PHONY: default check docs
12 |
--------------------------------------------------------------------------------
/vendor/github.com/juju/errors/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013, 2014 Canonical Ltd.
2 | // Licensed under the LGPLv3, see LICENCE file for details.
3 |
4 | /*
5 | [godoc-link-here]
6 |
7 | The juju/errors provides an easy way to annotate errors without losing the
8 | orginal error context.
9 |
10 | The exported `New` and `Errorf` functions are designed to replace the
11 | `errors.New` and `fmt.Errorf` functions respectively. The same underlying
12 | error is there, but the package also records the location at which the error
13 | was created.
14 |
15 | A primary use case for this library is to add extra context any time an
16 | error is returned from a function.
17 |
18 | if err := SomeFunc(); err != nil {
19 | return err
20 | }
21 |
22 | This instead becomes:
23 |
24 | if err := SomeFunc(); err != nil {
25 | return errors.Trace(err)
26 | }
27 |
28 | which just records the file and line number of the Trace call, or
29 |
30 | if err := SomeFunc(); err != nil {
31 | return errors.Annotate(err, "more context")
32 | }
33 |
34 | which also adds an annotation to the error.
35 |
36 | When you want to check to see if an error is of a particular type, a helper
37 | function is normally exported by the package that returned the error, like the
38 | `os` package does. The underlying cause of the error is available using the
39 | `Cause` function.
40 |
41 | os.IsNotExist(errors.Cause(err))
42 |
43 | The result of the `Error()` call on an annotated error is the annotations joined
44 | with colons, then the result of the `Error()` method for the underlying error
45 | that was the cause.
46 |
47 | err := errors.Errorf("original")
48 | err = errors.Annotatef(err, "context")
49 | err = errors.Annotatef(err, "more context")
50 | err.Error() -> "more context: context: original"
51 |
52 | Obviously recording the file, line and functions is not very useful if you
53 | cannot get them back out again.
54 |
55 | errors.ErrorStack(err)
56 |
57 | will return something like:
58 |
59 | first error
60 | github.com/juju/errors/annotation_test.go:193:
61 | github.com/juju/errors/annotation_test.go:194: annotation
62 | github.com/juju/errors/annotation_test.go:195:
63 | github.com/juju/errors/annotation_test.go:196: more context
64 | github.com/juju/errors/annotation_test.go:197:
65 |
66 | The first error was generated by an external system, so there was no location
67 | associated. The second, fourth, and last lines were generated with Trace calls,
68 | and the other two through Annotate.
69 |
70 | Sometimes when responding to an error you want to return a more specific error
71 | for the situation.
72 |
73 | if err := FindField(field); err != nil {
74 | return errors.Wrap(err, errors.NotFoundf(field))
75 | }
76 |
77 | This returns an error where the complete error stack is still available, and
78 | `errors.Cause()` will return the `NotFound` error.
79 |
80 | */
81 | package errors
82 |
--------------------------------------------------------------------------------
/vendor/github.com/juju/errors/error.go:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Canonical Ltd.
2 | // Licensed under the LGPLv3, see LICENCE file for details.
3 |
4 | package errors
5 |
6 | import (
7 | "fmt"
8 | "reflect"
9 | "runtime"
10 | )
11 |
12 | // Err holds a description of an error along with information about
13 | // where the error was created.
14 | //
15 | // It may be embedded in custom error types to add extra information that
16 | // this errors package can understand.
17 | type Err struct {
18 | // message holds an annotation of the error.
19 | message string
20 |
21 | // cause holds the cause of the error as returned
22 | // by the Cause method.
23 | cause error
24 |
25 | // previous holds the previous error in the error stack, if any.
26 | previous error
27 |
28 | // file and line hold the source code location where the error was
29 | // created.
30 | file string
31 | line int
32 | }
33 |
34 | // NewErr is used to return an Err for the purpose of embedding in other
35 | // structures. The location is not specified, and needs to be set with a call
36 | // to SetLocation.
37 | //
38 | // For example:
39 | // type FooError struct {
40 | // errors.Err
41 | // code int
42 | // }
43 | //
44 | // func NewFooError(code int) error {
45 | // err := &FooError{errors.NewErr("foo"), code}
46 | // err.SetLocation(1)
47 | // return err
48 | // }
49 | func NewErr(format string, args ...interface{}) Err {
50 | return Err{
51 | message: fmt.Sprintf(format, args...),
52 | }
53 | }
54 |
55 | // NewErrWithCause is used to return an Err with case by other error for the purpose of embedding in other
56 | // structures. The location is not specified, and needs to be set with a call
57 | // to SetLocation.
58 | //
59 | // For example:
60 | // type FooError struct {
61 | // errors.Err
62 | // code int
63 | // }
64 | //
65 | // func (e *FooError) Annotate(format string, args ...interface{}) error {
66 | // err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
67 | // err.SetLocation(1)
68 | // return err
69 | // })
70 | func NewErrWithCause(other error, format string, args ...interface{}) Err {
71 | return Err{
72 | message: fmt.Sprintf(format, args...),
73 | cause: Cause(other),
74 | previous: other,
75 | }
76 | }
77 |
78 | // Location is the file and line of where the error was most recently
79 | // created or annotated.
80 | func (e *Err) Location() (filename string, line int) {
81 | return e.file, e.line
82 | }
83 |
84 | // Underlying returns the previous error in the error stack, if any. A client
85 | // should not ever really call this method. It is used to build the error
86 | // stack and should not be introspected by client calls. Or more
87 | // specifically, clients should not depend on anything but the `Cause` of an
88 | // error.
89 | func (e *Err) Underlying() error {
90 | return e.previous
91 | }
92 |
93 | // The Cause of an error is the most recent error in the error stack that
94 | // meets one of these criteria: the original error that was raised; the new
95 | // error that was passed into the Wrap function; the most recently masked
96 | // error; or nil if the error itself is considered the Cause. Normally this
97 | // method is not invoked directly, but instead through the Cause stand alone
98 | // function.
99 | func (e *Err) Cause() error {
100 | return e.cause
101 | }
102 |
103 | // Message returns the message stored with the most recent location. This is
104 | // the empty string if the most recent call was Trace, or the message stored
105 | // with Annotate or Mask.
106 | func (e *Err) Message() string {
107 | return e.message
108 | }
109 |
110 | // Error implements error.Error.
111 | func (e *Err) Error() string {
112 | // We want to walk up the stack of errors showing the annotations
113 | // as long as the cause is the same.
114 | err := e.previous
115 | if !sameError(Cause(err), e.cause) && e.cause != nil {
116 | err = e.cause
117 | }
118 | switch {
119 | case err == nil:
120 | return e.message
121 | case e.message == "":
122 | return err.Error()
123 | }
124 | return fmt.Sprintf("%s: %v", e.message, err)
125 | }
126 |
127 | // SetLocation records the source location of the error at callDepth stack
128 | // frames above the call.
129 | func (e *Err) SetLocation(callDepth int) {
130 | _, file, line, _ := runtime.Caller(callDepth + 1)
131 | e.file = trimGoPath(file)
132 | e.line = line
133 | }
134 |
135 | // StackTrace returns one string for each location recorded in the stack of
136 | // errors. The first value is the originating error, with a line for each
137 | // other annotation or tracing of the error.
138 | func (e *Err) StackTrace() []string {
139 | return errorStack(e)
140 | }
141 |
142 | // Ideally we'd have a way to check identity, but deep equals will do.
143 | func sameError(e1, e2 error) bool {
144 | return reflect.DeepEqual(e1, e2)
145 | }
146 |
--------------------------------------------------------------------------------
/vendor/github.com/juju/errors/path.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013, 2014 Canonical Ltd.
2 | // Licensed under the LGPLv3, see LICENCE file for details.
3 |
4 | package errors
5 |
6 | import (
7 | "runtime"
8 | "strings"
9 | )
10 |
11 | // prefixSize is used internally to trim the user specific path from the
12 | // front of the returned filenames from the runtime call stack.
13 | var prefixSize int
14 |
15 | // goPath is the deduced path based on the location of this file as compiled.
16 | var goPath string
17 |
18 | func init() {
19 | _, file, _, ok := runtime.Caller(0)
20 | if file == "?" {
21 | return
22 | }
23 | if ok {
24 | // We know that the end of the file should be:
25 | // github.com/juju/errors/path.go
26 | size := len(file)
27 | suffix := len("github.com/juju/errors/path.go")
28 | goPath = file[:size-suffix]
29 | prefixSize = len(goPath)
30 | }
31 | }
32 |
33 | func trimGoPath(filename string) string {
34 | if strings.HasPrefix(filename, goPath) {
35 | return filename[prefixSize:]
36 | }
37 | return filename
38 | }
39 |
--------------------------------------------------------------------------------
/vendor/github.com/kataras/go-errors/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Gerasimos Maropoulos
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/github.com/kataras/go-errors/errors.go:
--------------------------------------------------------------------------------
1 | // Package errors helps you to write and design your own pre-defined errors, useful when you have a known list of errors
2 | package errors
3 |
4 | import (
5 | "fmt"
6 | "runtime"
7 | )
8 |
9 | const (
10 | // Version current version number
11 | Version = "0.0.3"
12 | )
13 |
14 | var (
15 | // Prefix the error prefix, applies to each error's message
16 | // defaults to Error:_
17 | Prefix = "Error: "
18 | // NewLine adds a new line to the end of each error's message
19 | // defaults to true
20 | NewLine = true
21 | )
22 |
23 | // Error holds the error message, this message never really changes
24 | type Error struct {
25 | message string
26 | appended bool
27 | }
28 |
29 | // New creates and returns an Error with a pre-defined user output message
30 | // all methods below that doesn't accept a pointer receiver because actualy they are not changing the original message
31 | func New(errMsg string) *Error {
32 | if NewLine {
33 | errMsg += "\n"
34 | }
35 | return &Error{message: Prefix + errMsg}
36 | }
37 |
38 | // String returns the error message
39 | func (e Error) String() string {
40 | return e.message
41 | }
42 |
43 | // Error returns the message of the actual error
44 | // implements the error
45 | func (e Error) Error() string {
46 | return e.String()
47 | }
48 |
49 | // Format returns a formatted new error based on the arguments
50 | // it does NOT change the original error's message
51 | func (e Error) Format(a ...interface{}) Error {
52 | e.message = fmt.Sprintf(e.message, a...)
53 | return e
54 | }
55 |
56 | // Append adds a message to the predefined error message and returns a new error
57 | // it does NOT change the original error's message
58 | func (e Error) Append(format string, a ...interface{}) Error {
59 | // eCp := *e
60 | if NewLine {
61 | format += "\n"
62 | }
63 | e.message += fmt.Sprintf(format, a...)
64 | e.appended = true
65 | return e
66 | }
67 |
68 | // AppendErr adds an error's message to the predefined error message and returns a new error
69 | // it does NOT change the original error's message
70 | func (e Error) AppendErr(err error) Error {
71 | return e.Append(err.Error())
72 | }
73 |
74 | // IsAppended returns true if the Error instance is created using original's Error.Append/AppendErr func
75 | func (e Error) IsAppended() bool {
76 | return e.appended
77 | }
78 |
79 | // With does the same thing as Format but it receives an error type which if it's nil it returns a nil error
80 | func (e Error) With(err error) error {
81 | if err == nil {
82 | return nil
83 | }
84 |
85 | return e.Format(err.Error())
86 | }
87 |
88 | // Panic output the message and after panics
89 | func (e Error) Panic() {
90 | _, fn, line, _ := runtime.Caller(1)
91 | errMsg := e.message
92 | errMsg = "\nCaller was: " + fmt.Sprintf("%s:%d", fn, line)
93 | panic(errMsg)
94 | }
95 |
96 | // Panicf output the formatted message and after panics
97 | func (e Error) Panicf(args ...interface{}) {
98 | _, fn, line, _ := runtime.Caller(1)
99 | errMsg := e.Format(args...).Error()
100 | errMsg = "\nCaller was: " + fmt.Sprintf("%s:%d", fn, line)
101 | panic(errMsg)
102 | }
103 |
--------------------------------------------------------------------------------
/vendor/github.com/microcosm-cc/bluemonday/LICENCE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, David Kitchen
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | * Neither the name of the organisation (Microcosm) nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/vendor/github.com/microcosm-cc/bluemonday/Makefile:
--------------------------------------------------------------------------------
1 | # Targets:
2 | #
3 | # all: Builds the code locally after testing
4 | #
5 | # fmt: Formats the source files
6 | # build: Builds the code locally
7 | # vet: Vets the code
8 | # lint: Runs lint over the code (you do not need to fix everything)
9 | # test: Runs the tests
10 | # cover: Gives you the URL to a nice test coverage report
11 | #
12 | # install: Builds, tests and installs the code locally
13 |
14 | .PHONY: all fmt build vet lint test cover clean install
15 |
16 | # The first target is always the default action if `make` is called without
17 | # args we build and install into $GOPATH so that it can just be run
18 |
19 | all: fmt vet test install
20 |
21 | fmt:
22 | @gofmt -w ./$*
23 |
24 | build: clean
25 | @go build
26 |
27 | vet:
28 | @vet *.go
29 |
30 | lint:
31 | @golint *.go
32 |
33 | test:
34 | @go test -v ./...
35 |
36 | cover: COVERAGE_FILE := coverage.out
37 | cover:
38 | @go test -coverprofile=$(COVERAGE_FILE) && \
39 | cover -html=$(COVERAGE_FILE) && rm $(COVERAGE_FILE)
40 |
41 | install: clean
42 | @go install ./...
43 |
--------------------------------------------------------------------------------
/vendor/github.com/microcosm-cc/bluemonday/cmd/sanitise_html_email/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package main demonstrates a HTML email cleaner.
3 |
4 | It should be noted that this uses bluemonday to sanitize the HTML but as it
5 | preserves the styling of the email this should not be considered a safe or XSS
6 | secure approach.
7 |
8 | It does function as a basic demonstration of how to take HTML emails, which are
9 | notorious for having inconsistent, obselete and poorly formatted HTML, and to
10 | use bluemonday to normalise the output.
11 | */
12 | package main
13 |
--------------------------------------------------------------------------------
/vendor/github.com/microcosm-cc/bluemonday/cmd/sanitise_html_email/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "log"
7 | "os"
8 | "regexp"
9 |
10 | "github.com/microcosm-cc/bluemonday"
11 | )
12 |
13 | var (
14 | // Color is a valid hex color or name of a web safe color
15 | Color = regexp.MustCompile(`(?i)^(#[0-9a-fA-F]{1,6}|black|silver|gray|white|maroon|red|purple|fuchsia|green|lime|olive|yellow|navy|blue|teal|aqua|orange|aliceblue|antiquewhite|aquamarine|azure|beige|bisque|blanchedalmond|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|gainsboro|ghostwhite|gold|goldenrod|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|limegreen|linen|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|oldlace|olivedrab|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|thistle|tomato|turquoise|violet|wheat|whitesmoke|yellowgreen|rebeccapurple)$`)
16 |
17 | // ButtonType is a button type, or a style type, i.e. "submit"
18 | ButtonType = regexp.MustCompile(`(?i)^[a-zA-Z][a-zA-Z-]{1,30}[a-zA-Z]$`)
19 |
20 | // StyleType is the valid type attribute on a style tag in the
21 | StyleType = regexp.MustCompile(`(?i)^text\/css$`)
22 | )
23 |
24 | func main() {
25 | // Define a policy, we are using the UGC policy as a base.
26 | p := bluemonday.UGCPolicy()
27 |
28 | // HTML email is often displayed in iframes and needs to preserve core
29 | // structure
30 | p.AllowDocType(true)
31 | p.AllowElements("html", "head", "body", "title")
32 |
33 | // There are not safe, and is only being done here to demonstrate how to
34 | // process HTML emails where styling has to be preserved. This is at the
35 | // expense of security.
36 | p.AllowAttrs("type").Matching(StyleType).OnElements("style")
37 | p.AllowAttrs("style").Globally()
38 |
39 | // HTML email frequently contains obselete and basic HTML
40 | p.AllowElements("font", "main", "nav", "header", "footer", "kbd", "legend")
41 |
42 | // Need to permit the style tag, and buttons are often found in emails (why?)
43 | p.AllowAttrs("type").Matching(ButtonType).OnElements("button")
44 |
45 | // HTML email tends to see the use of obselete spacing and styling attributes
46 | p.AllowAttrs("bgcolor", "color").Matching(Color).OnElements("basefont", "font", "hr")
47 | p.AllowAttrs("border").Matching(bluemonday.Integer).OnElements("img", "table")
48 | p.AllowAttrs("cellpadding", "cellspacing").Matching(bluemonday.Integer).OnElements("table")
49 |
50 | // Allow "class" attributes on all elements
51 | p.AllowStyling()
52 |
53 | // Allow images to be embedded via data-uri
54 | p.AllowDataURIImages()
55 |
56 | // Add "rel=nofollow" to links
57 | p.RequireNoFollowOnLinks(true)
58 | p.RequireNoFollowOnFullyQualifiedLinks(true)
59 |
60 | // Open external links in a new window/tab
61 | p.AddTargetBlankToFullyQualifiedLinks(true)
62 |
63 | // Read input from stdin so that this is a nice unix utility and can receive
64 | // piped input
65 | dirty, err := ioutil.ReadAll(os.Stdin)
66 | if err != nil {
67 | log.Fatal(err)
68 | }
69 |
70 | // Apply the policy and write to stdout
71 | fmt.Fprint(
72 | os.Stdout,
73 | p.Sanitize(
74 | string(dirty),
75 | ),
76 | )
77 | }
78 |
--------------------------------------------------------------------------------
/vendor/github.com/microcosm-cc/bluemonday/cmd/sanitise_ugc/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package main demonstrates a simple user generated content sanitizer.
3 |
4 | This is the configuration I use on the sites that I run, it allows a lot of safe
5 | HTML that in my case comes from the blackfriday markdown package. As markdown
6 | itself allows HTML the UGCPolicy includes most common HTML.
7 |
8 | CSS and JavaScript is excluded (not white-listed), as are form elements and most
9 | embedded media that isn't just an image or image map.
10 |
11 | As I'm paranoid, I also do not allow data-uri images and embeds.
12 | */
13 | package main
14 |
--------------------------------------------------------------------------------
/vendor/github.com/microcosm-cc/bluemonday/cmd/sanitise_ugc/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "log"
7 | "os"
8 |
9 | "github.com/microcosm-cc/bluemonday"
10 | )
11 |
12 | func main() {
13 | // Define a policy, we are using the UGC policy as a base.
14 | p := bluemonday.UGCPolicy()
15 |
16 | // Add "rel=nofollow" to links
17 | p.RequireNoFollowOnLinks(true)
18 | p.RequireNoFollowOnFullyQualifiedLinks(true)
19 |
20 | // Open external links in a new window/tab
21 | p.AddTargetBlankToFullyQualifiedLinks(true)
22 |
23 | // Read input from stdin so that this is a nice unix utility and can receive
24 | // piped input
25 | dirty, err := ioutil.ReadAll(os.Stdin)
26 | if err != nil {
27 | log.Fatal(err)
28 | }
29 |
30 | // Apply the policy and write to stdout
31 | fmt.Fprint(
32 | os.Stdout,
33 | p.Sanitize(
34 | string(dirty),
35 | ),
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/vendor/github.com/microcosm-cc/bluemonday/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014, David Kitchen
2 | //
3 | // All rights reserved.
4 | //
5 | // Redistribution and use in source and binary forms, with or without
6 | // modification, are permitted provided that the following conditions are met:
7 | //
8 | // * Redistributions of source code must retain the above copyright notice, this
9 | // list of conditions and the following disclaimer.
10 | //
11 | // * Redistributions in binary form must reproduce the above copyright notice,
12 | // this list of conditions and the following disclaimer in the documentation
13 | // and/or other materials provided with the distribution.
14 | //
15 | // * Neither the name of the organisation (Microcosm) nor the names of its
16 | // contributors may be used to endorse or promote products derived from
17 | // this software without specific prior written permission.
18 | //
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 | /*
31 | Package bluemonday provides a way of describing a whitelist of HTML elements
32 | and attributes as a policy, and for that policy to be applied to untrusted
33 | strings from users that may contain markup. All elements and attributes not on
34 | the whitelist will be stripped.
35 |
36 | The default bluemonday.UGCPolicy().Sanitize() turns this:
37 |
38 | Hello World
39 |
40 | Into the more harmless:
41 |
42 | Hello World
43 |
44 | And it turns this:
45 |
46 | XSS
47 |
48 | Into this:
49 |
50 | XSS
51 |
52 | Whilst still allowing this:
53 |
54 |
55 |
56 |
57 |
58 | To pass through mostly unaltered (it gained a rel="nofollow"):
59 |
60 |
61 |
62 |
63 |
64 | The primary purpose of bluemonday is to take potentially unsafe user generated
65 | content (from things like Markdown, HTML WYSIWYG tools, etc) and make it safe
66 | for you to put on your website.
67 |
68 | It protects sites against XSS (http://en.wikipedia.org/wiki/Cross-site_scripting)
69 | and other malicious content that a user interface may deliver. There are many
70 | vectors for an XSS attack (https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet)
71 | and the safest thing to do is to sanitize user input against a known safe list
72 | of HTML elements and attributes.
73 |
74 | Note: You should always run bluemonday after any other processing.
75 |
76 | If you use blackfriday (https://github.com/russross/blackfriday) or
77 | Pandoc (http://johnmacfarlane.net/pandoc/) then bluemonday should be run after
78 | these steps. This ensures that no insecure HTML is introduced later in your
79 | process.
80 |
81 | bluemonday is heavily inspired by both the OWASP Java HTML Sanitizer
82 | (https://code.google.com/p/owasp-java-html-sanitizer/) and the HTML Purifier
83 | (http://htmlpurifier.org/).
84 |
85 | We ship two default policies, one is bluemonday.StrictPolicy() and can be
86 | thought of as equivalent to stripping all HTML elements and their attributes as
87 | it has nothing on it's whitelist.
88 |
89 | The other is bluemonday.UGCPolicy() and allows a broad selection of HTML
90 | elements and attributes that are safe for user generated content. Note that
91 | this policy does not whitelist iframes, object, embed, styles, script, etc.
92 |
93 | The essence of building a policy is to determine which HTML elements and
94 | attributes are considered safe for your scenario. OWASP provide an XSS
95 | prevention cheat sheet ( https://www.google.com/search?q=xss+prevention+cheat+sheet )
96 | to help explain the risks, but essentially:
97 |
98 | 1. Avoid whitelisting anything other than plain HTML elements
99 | 2. Avoid whitelisting `script`, `style`, `iframe`, `object`, `embed`, `base`
100 | elements
101 | 3. Avoid whitelisting anything other than plain HTML elements with simple
102 | values that you can match to a regexp
103 | */
104 | package bluemonday
105 |
--------------------------------------------------------------------------------
/vendor/github.com/russross/blackfriday/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Blackfriday is distributed under the Simplified BSD License:
2 |
3 | > Copyright © 2011 Russ Ross
4 | > All rights reserved.
5 | >
6 | > Redistribution and use in source and binary forms, with or without
7 | > modification, are permitted provided that the following conditions
8 | > are met:
9 | >
10 | > 1. Redistributions of source code must retain the above copyright
11 | > notice, this list of conditions and the following disclaimer.
12 | >
13 | > 2. Redistributions in binary form must reproduce the above
14 | > copyright notice, this list of conditions and the following
15 | > disclaimer in the documentation and/or other materials provided with
16 | > the distribution.
17 | >
18 | > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | > "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | > LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 | > FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 | > COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 | > INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 | > BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | > LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | > CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 | > LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 | > ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | > POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Dmitri Shuralyov
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/vendor/github.com/shurcooL/sanitized_anchor_name/main.go:
--------------------------------------------------------------------------------
1 | // Package sanitized_anchor_name provides a func to create sanitized anchor names.
2 | //
3 | // Its logic can be reused by multiple packages to create interoperable anchor names
4 | // and links to those anchors.
5 | //
6 | // At this time, it does not try to ensure that generated anchor names
7 | // are unique, that responsibility falls on the caller.
8 | package sanitized_anchor_name // import "github.com/shurcooL/sanitized_anchor_name"
9 |
10 | import "unicode"
11 |
12 | // Create returns a sanitized anchor name for the given text.
13 | func Create(text string) string {
14 | var anchorName []rune
15 | var futureDash = false
16 | for _, r := range []rune(text) {
17 | switch {
18 | case unicode.IsLetter(r) || unicode.IsNumber(r):
19 | if futureDash && len(anchorName) > 0 {
20 | anchorName = append(anchorName, '-')
21 | }
22 | futureDash = false
23 | anchorName = append(anchorName, unicode.ToLower(r))
24 | default:
25 | futureDash = true
26 | }
27 | }
28 | return string(anchorName)
29 | }
30 |
--------------------------------------------------------------------------------
/vendor/github.com/valyala/bytebufferpool/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/vendor/github.com/valyala/bytebufferpool/bytebuffer.go:
--------------------------------------------------------------------------------
1 | package bytebufferpool
2 |
3 | import "io"
4 |
5 | // ByteBuffer provides byte buffer, which can be used for minimizing
6 | // memory allocations.
7 | //
8 | // ByteBuffer may be used with functions appending data to the given []byte
9 | // slice. See example code for details.
10 | //
11 | // Use Get for obtaining an empty byte buffer.
12 | type ByteBuffer struct {
13 |
14 | // B is a byte buffer to use in append-like workloads.
15 | // See example code for details.
16 | B []byte
17 | }
18 |
19 | // Len returns the size of the byte buffer.
20 | func (b *ByteBuffer) Len() int {
21 | return len(b.B)
22 | }
23 |
24 | // ReadFrom implements io.ReaderFrom.
25 | //
26 | // The function appends all the data read from r to b.
27 | func (b *ByteBuffer) ReadFrom(r io.Reader) (int64, error) {
28 | p := b.B
29 | nStart := int64(len(p))
30 | nMax := int64(cap(p))
31 | n := nStart
32 | if nMax == 0 {
33 | nMax = 64
34 | p = make([]byte, nMax)
35 | } else {
36 | p = p[:nMax]
37 | }
38 | for {
39 | if n == nMax {
40 | nMax *= 2
41 | bNew := make([]byte, nMax)
42 | copy(bNew, p)
43 | p = bNew
44 | }
45 | nn, err := r.Read(p[n:])
46 | n += int64(nn)
47 | if err != nil {
48 | b.B = p[:n]
49 | n -= nStart
50 | if err == io.EOF {
51 | return n, nil
52 | }
53 | return n, err
54 | }
55 | }
56 | }
57 |
58 | // WriteTo implements io.WriterTo.
59 | func (b *ByteBuffer) WriteTo(w io.Writer) (int64, error) {
60 | n, err := w.Write(b.B)
61 | return int64(n), err
62 | }
63 |
64 | // Bytes returns b.B, i.e. all the bytes accumulated in the buffer.
65 | //
66 | // The purpose of this function is bytes.Buffer compatibility.
67 | func (b *ByteBuffer) Bytes() []byte {
68 | return b.B
69 | }
70 |
71 | // Write implements io.Writer - it appends p to ByteBuffer.B
72 | func (b *ByteBuffer) Write(p []byte) (int, error) {
73 | b.B = append(b.B, p...)
74 | return len(p), nil
75 | }
76 |
77 | // WriteByte appends the byte c to the buffer.
78 | //
79 | // The purpose of this function is bytes.Buffer compatibility.
80 | //
81 | // The function always returns nil.
82 | func (b *ByteBuffer) WriteByte(c byte) error {
83 | b.B = append(b.B, c)
84 | return nil
85 | }
86 |
87 | // WriteString appends s to ByteBuffer.B.
88 | func (b *ByteBuffer) WriteString(s string) (int, error) {
89 | b.B = append(b.B, s...)
90 | return len(s), nil
91 | }
92 |
93 | // Set sets ByteBuffer.B to p.
94 | func (b *ByteBuffer) Set(p []byte) {
95 | b.B = append(b.B[:0], p...)
96 | }
97 |
98 | // SetString sets ByteBuffer.B to s.
99 | func (b *ByteBuffer) SetString(s string) {
100 | b.B = append(b.B[:0], s...)
101 | }
102 |
103 | // String returns string representation of ByteBuffer.B.
104 | func (b *ByteBuffer) String() string {
105 | return string(b.B)
106 | }
107 |
108 | // Reset makes ByteBuffer.B empty.
109 | func (b *ByteBuffer) Reset() {
110 | b.B = b.B[:0]
111 | }
112 |
--------------------------------------------------------------------------------
/vendor/github.com/valyala/bytebufferpool/bytebuffer_test.go:
--------------------------------------------------------------------------------
1 | package bytebufferpool
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "io"
7 | "testing"
8 | "time"
9 | )
10 |
11 | func TestByteBufferReadFrom(t *testing.T) {
12 | prefix := "foobar"
13 | expectedS := "asadfsdafsadfasdfisdsdfa"
14 | prefixLen := int64(len(prefix))
15 | expectedN := int64(len(expectedS))
16 |
17 | var bb ByteBuffer
18 | bb.WriteString(prefix)
19 |
20 | rf := (io.ReaderFrom)(&bb)
21 | for i := 0; i < 20; i++ {
22 | r := bytes.NewBufferString(expectedS)
23 | n, err := rf.ReadFrom(r)
24 | if n != expectedN {
25 | t.Fatalf("unexpected n=%d. Expecting %d. iteration %d", n, expectedN, i)
26 | }
27 | if err != nil {
28 | t.Fatalf("unexpected error: %s", err)
29 | }
30 | bbLen := int64(bb.Len())
31 | expectedLen := prefixLen + int64(i+1)*expectedN
32 | if bbLen != expectedLen {
33 | t.Fatalf("unexpected byteBuffer length: %d. Expecting %d", bbLen, expectedLen)
34 | }
35 | for j := 0; j < i; j++ {
36 | start := prefixLen + int64(j)*expectedN
37 | b := bb.B[start : start+expectedN]
38 | if string(b) != expectedS {
39 | t.Fatalf("unexpected byteBuffer contents: %q. Expecting %q", b, expectedS)
40 | }
41 | }
42 | }
43 | }
44 |
45 | func TestByteBufferWriteTo(t *testing.T) {
46 | expectedS := "foobarbaz"
47 | var bb ByteBuffer
48 | bb.WriteString(expectedS[:3])
49 | bb.WriteString(expectedS[3:])
50 |
51 | wt := (io.WriterTo)(&bb)
52 | var w bytes.Buffer
53 | for i := 0; i < 10; i++ {
54 | n, err := wt.WriteTo(&w)
55 | if n != int64(len(expectedS)) {
56 | t.Fatalf("unexpected n returned from WriteTo: %d. Expecting %d", n, len(expectedS))
57 | }
58 | if err != nil {
59 | t.Fatalf("unexpected error: %s", err)
60 | }
61 | s := string(w.Bytes())
62 | if s != expectedS {
63 | t.Fatalf("unexpected string written %q. Expecting %q", s, expectedS)
64 | }
65 | w.Reset()
66 | }
67 | }
68 |
69 | func TestByteBufferGetPutSerial(t *testing.T) {
70 | testByteBufferGetPut(t)
71 | }
72 |
73 | func TestByteBufferGetPutConcurrent(t *testing.T) {
74 | concurrency := 10
75 | ch := make(chan struct{}, concurrency)
76 | for i := 0; i < concurrency; i++ {
77 | go func() {
78 | testByteBufferGetPut(t)
79 | ch <- struct{}{}
80 | }()
81 | }
82 |
83 | for i := 0; i < concurrency; i++ {
84 | select {
85 | case <-ch:
86 | case <-time.After(time.Second):
87 | t.Fatalf("timeout!")
88 | }
89 | }
90 | }
91 |
92 | func testByteBufferGetPut(t *testing.T) {
93 | for i := 0; i < 10; i++ {
94 | expectedS := fmt.Sprintf("num %d", i)
95 | b := Get()
96 | b.B = append(b.B, "num "...)
97 | b.B = append(b.B, fmt.Sprintf("%d", i)...)
98 | if string(b.B) != expectedS {
99 | t.Fatalf("unexpected result: %q. Expecting %q", b.B, expectedS)
100 | }
101 | Put(b)
102 | }
103 | }
104 |
105 | func testByteBufferGetString(t *testing.T) {
106 | for i := 0; i < 10; i++ {
107 | expectedS := fmt.Sprintf("num %d", i)
108 | b := Get()
109 | b.SetString(expectedS)
110 | if b.String() != expectedS {
111 | t.Fatalf("unexpected result: %q. Expecting %q", b.B, expectedS)
112 | }
113 | Put(b)
114 | }
115 | }
116 |
117 | func TestByteBufferGetStringSerial(t *testing.T) {
118 | testByteBufferGetString(t)
119 | }
120 |
121 | func TestByteBufferGetStringConcurrent(t *testing.T) {
122 | concurrency := 10
123 | ch := make(chan struct{}, concurrency)
124 | for i := 0; i < concurrency; i++ {
125 | go func() {
126 | testByteBufferGetString(t)
127 | ch <- struct{}{}
128 | }()
129 | }
130 |
131 | for i := 0; i < concurrency; i++ {
132 | select {
133 | case <-ch:
134 | case <-time.After(time.Second):
135 | t.Fatalf("timeout!")
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/vendor/github.com/valyala/bytebufferpool/pool.go:
--------------------------------------------------------------------------------
1 | package bytebufferpool
2 |
3 | import (
4 | "sort"
5 | "sync"
6 | "sync/atomic"
7 | )
8 |
9 | const (
10 | minBitSize = 6 // 2**6=64 is a CPU cache line size
11 | steps = 20
12 |
13 | minSize = 1 << minBitSize
14 | maxSize = 1 << (minBitSize + steps - 1)
15 |
16 | calibrateCallsThreshold = 42000
17 | maxPercentile = 0.95
18 | )
19 |
20 | // Pool represents byte buffer pool.
21 | //
22 | // Distinct pools may be used for distinct types of byte buffers.
23 | // Properly determined byte buffer types with their own pools may help reducing
24 | // memory waste.
25 | type Pool struct {
26 | calls [steps]uint64
27 | calibrating uint64
28 |
29 | defaultSize uint64
30 | maxSize uint64
31 |
32 | pool sync.Pool
33 | }
34 |
35 | var defaultPool Pool
36 |
37 | // Get returns an empty byte buffer from the pool.
38 | //
39 | // Got byte buffer may be returned to the pool via Put call.
40 | // This reduces the number of memory allocations required for byte buffer
41 | // management.
42 | func Get() *ByteBuffer { return defaultPool.Get() }
43 |
44 | // Get returns new byte buffer with zero length.
45 | //
46 | // The byte buffer may be returned to the pool via Put after the use
47 | // in order to minimize GC overhead.
48 | func (p *Pool) Get() *ByteBuffer {
49 | v := p.pool.Get()
50 | if v != nil {
51 | return v.(*ByteBuffer)
52 | }
53 | return &ByteBuffer{
54 | B: make([]byte, 0, atomic.LoadUint64(&p.defaultSize)),
55 | }
56 | }
57 |
58 | // Put returns byte buffer to the pool.
59 | //
60 | // ByteBuffer.B mustn't be touched after returning it to the pool.
61 | // Otherwise data races will occur.
62 | func Put(b *ByteBuffer) { defaultPool.Put(b) }
63 |
64 | // Put releases byte buffer obtained via Get to the pool.
65 | //
66 | // The buffer mustn't be accessed after returning to the pool.
67 | func (p *Pool) Put(b *ByteBuffer) {
68 | idx := index(len(b.B))
69 |
70 | if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold {
71 | p.calibrate()
72 | }
73 |
74 | maxSize := int(atomic.LoadUint64(&p.maxSize))
75 | if maxSize == 0 || cap(b.B) <= maxSize {
76 | b.Reset()
77 | p.pool.Put(b)
78 | }
79 | }
80 |
81 | func (p *Pool) calibrate() {
82 | if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) {
83 | return
84 | }
85 |
86 | a := make(callSizes, 0, steps)
87 | var callsSum uint64
88 | for i := uint64(0); i < steps; i++ {
89 | calls := atomic.SwapUint64(&p.calls[i], 0)
90 | callsSum += calls
91 | a = append(a, callSize{
92 | calls: calls,
93 | size: minSize << i,
94 | })
95 | }
96 | sort.Sort(a)
97 |
98 | defaultSize := a[0].size
99 | maxSize := defaultSize
100 |
101 | maxSum := uint64(float64(callsSum) * maxPercentile)
102 | callsSum = 0
103 | for i := 0; i < steps; i++ {
104 | if callsSum > maxSum {
105 | break
106 | }
107 | callsSum += a[i].calls
108 | size := a[i].size
109 | if size > maxSize {
110 | maxSize = size
111 | }
112 | }
113 |
114 | atomic.StoreUint64(&p.defaultSize, defaultSize)
115 | atomic.StoreUint64(&p.maxSize, maxSize)
116 |
117 | atomic.StoreUint64(&p.calibrating, 0)
118 | }
119 |
120 | type callSize struct {
121 | calls uint64
122 | size uint64
123 | }
124 |
125 | type callSizes []callSize
126 |
127 | func (ci callSizes) Len() int {
128 | return len(ci)
129 | }
130 |
131 | func (ci callSizes) Less(i, j int) bool {
132 | return ci[i].calls > ci[j].calls
133 | }
134 |
135 | func (ci callSizes) Swap(i, j int) {
136 | ci[i], ci[j] = ci[j], ci[i]
137 | }
138 |
139 | func index(n int) int {
140 | n--
141 | n >>= minBitSize
142 | idx := 0
143 | for n > 0 {
144 | n >>= 1
145 | idx++
146 | }
147 | if idx >= steps {
148 | idx = steps - 1
149 | }
150 | return idx
151 | }
152 |
--------------------------------------------------------------------------------