tyler-sommer / stick Goto Github PK
View Code? Open in Web Editor NEWA golang port of the Twig templating engine
License: MIT License
A golang port of the Twig templating engine
License: MIT License
A template like this: {{ x is defined ? 1 : 0 }}
results in parse: expected "PRINT_CLOSE", got "PUNCTUATION"
Similarly, this {% set y = x is defined ? 1 : 0 %}
results in parse: expected "TAG_CLOSE", got "PUNCTUATION"
PS. There's a chance I'll find the time and motivation to fix this (and other such issues I may run into), so any tips or pointers about the codebase would be welcome ๐
I see a panic while parsing this:
{{ foo.bar() }}
panic: reflect: call of reflect.Value.Type on zero Value
... better would be an error.
Hi @tyler-sommer ,
First I would like to thank you for your good work.
I have a question why have you opted for Execute
rather than Render
?
Doesn't render makes api vice very close to Twig itself ?
Hi, is stick support Revel templates? Can I adapt stick into Revel without risk? Thanks
See #17.
The "with" syntax detailed here that is used to inject variables into an included template doesn't seem to work:
// fragment.twig
{{ foo }}
// main.twig
{% include "fragment.twig" with {"foo": "bar"} %}
The error is:
parse: unexpected token "HASH_OPEN" on line 1, column 31
Many thanks for this great package!
I really needed a simple and extensible stand alone template parser like this.
I've managed to create additional filters, I liked how easy I could accomplish this.
Mike
import (
"log"
"os"
"github.com/tyler-sommer/stick"
)
func main() {
env := stick.New(nil)
if err := env.Execute("Hello, {{ order }}!", os.Stdout, map[string]stick.Value{"order": "ABCD"}); err != nil {
log.Fatal(err)
}
}
Something like this causes error parse: unexpected token "OPERATOR" on line 1, column 10
We've been using it in production and since had the issue described in #44
Although we can build our project using the current HEAD, I would suggest creating a new v1.0.4
tag for it since it would include
this important fix.
Thanks for the awesome job!
Hi Tyler it's me again :) It seems like if {% if true or false %}
returns false
For example:
package main
import (
"os"
"github.com/tyler-sommer/stick"
)
func main() {
env := stick.New(nil); // A nil loader means stick will simply execute
// the string passed into env.Execute.
// Templates receive a map of string to any value.
p := map[string]stick.Value{"name": "World"}
// Substitute os.Stdout with any io.Writer.
env.Execute(`{% set item1 = "orange" %} {% set item2 = "apple" %} {% if item1 == "banana" or item2 == "apple" %} At least one item is correct {% else %} neither item is correct {% endif %}`, os.Stdout, p)
}
It will print neither item is correct
.
I will have a look into this as well :)
Hi Tyler, I was trying to do something like the following
package main
import (
"github.com/tyler-sommer/stick"
"os"
"fmt"
)
func main() {
env := stick.New(nil);
p := map[string]stick.Value{"toothbrush": map[string]int{"cost":100}, "toothpaste":map[string]int{"cost":200},}
err := env.Execute(" Hello, {% if toothbrush.cost == toothpaste.cost %} same price {% endif %}", os.Stdout, p)
if err != nil {
fmt.Println(err)
}
}
It was throwing an error expected "TAG_CLOSE", got "PUNCTUATION" on line 1, column 43
This seems like a bug in the library?
The following...
{% set foo = ["bar", "baz"] %}
... gives an error:
parse: unexpected token "ARRAY_OPEN"
I moved the Twig-compatibility related extensions to the subpackage github.com/tyler-sommer/stick/twig.
This impacts a couple of things:
stick
is now solely a parser and template executor that aims to provide the same feature-set as the Twig language itself sans core extensions. To get a more Twig-like experience, including the expected auto-escaping, filters, functions, and tests, use github.com/tyler-sommer/stick/twig.stick.New()
now creates a completely bare executing environment.twig.New()
creates a more Twig-compatible environment with the expected filters and auto-escaping (and is under development)It boils down to:
stick.New()
before, switch to twig.New()
.stick.NewEnv()
before, use stick.New()
instead.Please open an issue if you run into any problems or have any feedback.
Auto escaping work fine for top level variables but ignores nested
Hi,
Is there any tools which integrate stick with golang iris?
Say if we have a file test.twig like following
{% if 1 == 1 %}
1 equals 1
{% endif %}
Our script to render this template is as following
fsRoot, _ := os.Getwd()
env := stick.New(stick.NewFilesystemLoader(fsRoot))
p = map[string]stick.Value{"name": "World"}
env.Execute("test.twig", os.Stdout, p)
It should print "1 equals 1", but right now it is not printing anything.
Did I miss something here or is this a bug we need to fix?
There are several areas that could use some tweaking with regard to error handling in Stick. This issue will be used to track and explain the reasoning behind these changes.
Each section below describes a different category of improvement. Tasks to carry out these improvements are defined together at the end, grouped by category.
Incomplete switch statements with no default handling may silently fail which could lead to frustration if a user encounters this behavior.
func (s *state) evalExpr(node parse.Node)
in exec.go in two places
func (s *state) walkChild(node parse.Node)
in exec.goThese cases are unlikely to encounter these silent failures in normal operation ("should never happen" barring the existence of a bug), but anyone hacking on stick itself may experience frustration when something isn't working and there is no hint as to what's going on.
Fixing these is technically a BC break as any templates relying on these silent failures will now fail to execute, returning an error instead. However, I don't think this is a real concern in practice and fixing these does not warrant a major version bump.
User-defined additions to Stick do not currently support returning any error. This results in needing to return some "empty" value rather than trying to signal an error.
I'm a little bit on the fence on whether some of these should be fixed. I see two main considerations:
Behavior in Twig itself is fairly loose and template execution generally tends to be forgiving of type mismatches and failed coercions. In Twig, user-defined functionality would need to throw an exception which would interrupt template execution. This can also be done in Go, if desired, with panic()
. However, in many places it makes sense to just return some sensible "empty" value rather than halting template execution. Using panic()
is also generally kind of smelly, though, so I hesitate to make that the go-to solution.
On the flip side, the current situation can lead to difficult to debug situations where user-defined functionality is not working as expected and there is no sign of what's going on because any error is being silently thrown away. Of course, logging could be used to provide some clue to the user.
One final factor to consider here is modifying the affected method signatures to return an error (arguably the best choice) would be a fairly major BC break, requiring all existing user-defined code to be updated. This would probably warrant a major version bump.
panic()
in user-defined code and convert it to an error
using recover()
during parsing (for NodeVisitors) and template execution.
Error messages throughout Stick are inconsistent and could use some attention.
These are relatively minor, though any code expecting specific error messages may stop working when the messages change. I think this is unlikely and don't consider this reason enough to bump the major version, however.
recover()
handlers to convert panics to errors during parsing and template execution.Env
and pass that into state
.parse: expected "ARRAY_CLOSE", got "PUNCTUATION" in
{{ prices[item.ID] }}
parse: expected "TAG_CLOSE", got "PUNCTUATION" in
{{ get_index(item.ID, prices)*item.Quantity }}
When trying to implement the batch twig filter I get a parse error.
Here is a small program to replicate the problem. It contains the test case and the expected output
package main
import (
"github.com/tyler-sommer/stick"
"os"
)
func main() {
env := stick.NewEnv(nil)
template := "{% for row in items|batch(3, 'No Item') %}{% for item in row %}{{ item }}.{% endfor %}.{% endfor %}"
println("Expected: 1.2.3..4.5.6..7.8.No Item..")
data := map[string]stick.Value{"items":[]int{1, 2, 3, 4, 5, 6, 7, 8}}
print("Actual: ")
err := env.Execute(template, os.Stdout, data)
println()
if nil != err {
println(err.Error())
}
}
The programs output is:
~/golang/src$ go run test-stick.go
Expected: 1.2.3..4.5.6..7.8.No Item..
Actual:
parse: expected "NUMBER", got "STRING_OPEN" on line 1, column 29
I have verified that this template syntax works with twig
The syntax for twig comments doesn't seem to work:
{# foo #}
Gives an error: Unknown node Text( foo )
I'd like to use this format of the set tag, but it doesn't appear to be implemented (results in a parse error)
{% set foo %}
<div id="pagination">
...
</div>
{% endset %}
Any plans to implement this in the future?
Just wanted to say thanks for building this lib, I really look forward to seeing it completed! Keep up the great work, sorry I can't contribute. Love twig in PHP and look forward to using it with Go!
Something I do with twig
in php like in the j2
files I have shown below. This doesn't seem to work in stick. I've narrowed it down to parent()
being the culprit. Stick just kindof gives up after hitting that.
This library at least got further than some of the other's I've checked out for jinjas templates.
I'd be happy to contribute, but I would be learning from the ground up on this stuff. If no one else has time to really look into this, if you can point me in the right direction on learning this stuff from the ground up, I'm more than happy to put some of my free time into learning this a bit and throwing in a pull request when I patch it for myself.
templates/page1.j2
{% extends "base.j2" %}
{% block title %} - More to life than just fun!{% endblock %}
{% block head %}
{{ parent() }}
{% endblock %}
{% block content %}
Content goes here.... PAGE 1
{{ a }}
{{ b }}
{% endblock %}
templates/base.j2
<!doctype html>
<html lang="en">
<head>
{% block head %}
<title>{{ sitename }}{% block title %}{% endblock %}</title>
{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
main.go
package main
import (
"github.com/tyler-sommer/stick/twig"
"github.com/tyler-sommer/stick"
"os"
)
func main() {
env := twig.New(stick.NewFilesystemLoader("./templates/"))
env.Execute("page1.j2", os.Stdout, map[string]stick.Value{ "sitename": "Somesite!" })
}
Hi there, (love this package, thank you soooo much for it!!)
I'm getting an error when I access a missing key in a map (originating here: https://github.com/tyler-sommer/stick/blob/master/value.go#L242) and I don't seem to find a way to suppress/avoid it.
In Twig, there is a strict_variables
setting which causes this access to return null (https://twig.symfony.com/doc/3.x/templates.html#variables) and in twig I could check for the existence of the variable without triggering the error.
Specifically, I'm using this package to render arbitrary json data provided as map[string]interface{}
, for example:
{ "data": { "foo": "bar" }}
and I'm trying to handle the expression {{ data.missing }}
without running into the error. I would like it to just output empty string if missing
is not defined on data
.
Am I overlooking a way to do this? Thank you for your help!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.