-
-
Notifications
You must be signed in to change notification settings - Fork 280
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add experimental arbitrary Go code support (#713)
Co-authored-by: Adrian Hesketh <adrianhesketh@hushmail.com>
- Loading branch information
Showing
18 changed files
with
275 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
0.2.688 | ||
0.2.692 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// This package is inspired by the GOEXPERIMENT approach of allowing feature flags for experimenting with breaking changes. | ||
package cfg | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
) | ||
|
||
type Flags struct { | ||
// RawGo will enable the support of arbibrary Go code in templates. | ||
RawGo bool | ||
} | ||
|
||
var Experiment = parse() | ||
|
||
func parse() *Flags { | ||
m := map[string]bool{} | ||
for _, f := range strings.Split(os.Getenv("TEMPL_EXPERIMENT"), ",") { | ||
m[strings.ToLower(f)] = true | ||
} | ||
|
||
return &Flags{ | ||
RawGo: m["rawgo"], | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Raw Go | ||
|
||
:::caution | ||
This page describes functionality that is experimental, not enabled by default, and may change or be removed in future versions. | ||
|
||
To enable this feature run the generation step with the `rawgo` experiment flag: `TEMPL_EXPERIMENT=rawgo templ generate` | ||
|
||
You will also need to set the `TEMPL_EXPERIMENT=rawgo` environment variable at your system level or within your editor to enable LSP behavior. | ||
::: | ||
|
||
For some more advanced use cases it may be useful to write Go code statements in your template. | ||
|
||
Use the `{{ ... }}` syntax for this. | ||
|
||
## Variable declarations | ||
|
||
Scoped variables can be created using this syntax, to reduce the need for multiple function calls. | ||
|
||
```templ title="component.templ" | ||
package main | ||
templ nameList(items []Item) { | ||
{{ first := items[0] }} | ||
<p> | ||
{ first.Name } | ||
</p> | ||
} | ||
``` | ||
|
||
```html title="Output" | ||
<p>A</p> | ||
``` |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package parser | ||
|
||
import ( | ||
"github.com/a-h/parse" | ||
"github.com/a-h/templ/cfg" | ||
"github.com/a-h/templ/parser/v2/goexpression" | ||
) | ||
|
||
var goCode = parse.Func(func(pi *parse.Input) (n Node, ok bool, err error) { | ||
if !cfg.Experiment.RawGo { | ||
return | ||
} | ||
// Check the prefix first. | ||
if _, ok, err = parse.Or(parse.String("{{ "), parse.String("{{")).Parse(pi); err != nil || !ok { | ||
return | ||
} | ||
|
||
// Once we have a prefix, we must have an expression that returns a string, with optional err. | ||
l := pi.Position().Line | ||
var r GoCode | ||
if r.Expression, err = parseGo("go code", pi, goexpression.Expression); err != nil { | ||
return r, false, err | ||
} | ||
|
||
if l != pi.Position().Line { | ||
r.Multiline = true | ||
} | ||
|
||
// Clear any optional whitespace. | ||
_, _, _ = parse.OptionalWhitespace.Parse(pi) | ||
|
||
// }} | ||
if _, ok, err = dblCloseBraceWithOptionalPadding.Parse(pi); err != nil || !ok { | ||
err = parse.Error("go code: missing close braces", pi.Position()) | ||
return | ||
} | ||
|
||
// Parse trailing whitespace. | ||
ws, _, err := parse.Whitespace.Parse(pi) | ||
if err != nil { | ||
return r, false, err | ||
} | ||
r.TrailingSpace, err = NewTrailingSpace(ws) | ||
if err != nil { | ||
return r, false, err | ||
} | ||
|
||
return r, true, nil | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package parser | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/a-h/parse" | ||
"github.com/a-h/templ/cfg" | ||
"github.com/google/go-cmp/cmp" | ||
) | ||
|
||
func TestGoCodeParser(t *testing.T) { | ||
flagVal := cfg.Experiment.RawGo | ||
cfg.Experiment.RawGo = true | ||
defer func() { | ||
cfg.Experiment.RawGo = flagVal | ||
}() | ||
|
||
tests := []struct { | ||
name string | ||
input string | ||
expected GoCode | ||
}{ | ||
{ | ||
name: "basic expression", | ||
input: `{{ p := "this" }}`, | ||
expected: GoCode{ | ||
Expression: Expression{ | ||
Value: `p := "this"`, | ||
Range: Range{ | ||
From: Position{ | ||
Index: 3, | ||
Line: 0, | ||
Col: 3, | ||
}, | ||
To: Position{ | ||
Index: 14, | ||
Line: 0, | ||
Col: 14, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "basic expression, no space", | ||
input: `{{p:="this"}}`, | ||
expected: GoCode{ | ||
Expression: Expression{ | ||
Value: `p:="this"`, | ||
Range: Range{ | ||
From: Position{ | ||
Index: 2, | ||
Line: 0, | ||
Col: 2, | ||
}, | ||
To: Position{ | ||
Index: 11, | ||
Line: 0, | ||
Col: 11, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "multiline function decl", | ||
input: `{{ | ||
p := func() { | ||
dosomething() | ||
} | ||
}}`, | ||
expected: GoCode{ | ||
Expression: Expression{ | ||
Value: ` | ||
p := func() { | ||
dosomething() | ||
}`, | ||
Range: Range{ | ||
From: Position{ | ||
Index: 2, | ||
Line: 0, | ||
Col: 2, | ||
}, | ||
To: Position{ | ||
Index: 45, | ||
Line: 3, | ||
Col: 5, | ||
}, | ||
}, | ||
}, | ||
Multiline: true, | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
tt := tt | ||
t.Run(tt.name, func(t *testing.T) { | ||
input := parse.NewInput(tt.input) | ||
an, ok, err := goCode.Parse(input) | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
if !ok { | ||
t.Fatalf("unexpected failure for input %q", tt.input) | ||
} | ||
actual := an.(GoCode) | ||
if diff := cmp.Diff(tt.expected, actual); diff != "" { | ||
t.Error(diff) | ||
} | ||
|
||
// Check the index. | ||
cut := tt.input[actual.Expression.Range.From.Index:actual.Expression.Range.To.Index] | ||
if tt.expected.Expression.Value != cut { | ||
t.Errorf("range, expected %q, got %q", tt.expected.Expression.Value, cut) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters