Skip to content

Commit 02ed092

Browse files
committed
feat: add generation feature
1 parent 1b9a089 commit 02ed092

13 files changed

+517
-110
lines changed

.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.3.836
1+
0.3.836

generator/generator.go

+16-38
Original file line numberDiff line numberDiff line change
@@ -1475,22 +1475,20 @@ func (g *generator) writeScriptContents(indentLevel int, c parser.ScriptContents
14751475
return nil
14761476
}
14771477
// This is a JS expression and can be written directly to the output.
1478-
_, err := g.w.Write(*c.Value)
1479-
return err
1478+
return g.writeText(indentLevel, parser.Text{Value: *c.Value})
14801479
}
14811480
if c.GoCode != nil {
1482-
// This is a Go code block. The code needs to be evaluated, and the result written to the output
1483-
// using the correct JS and HTML escaping based on whether the expression output is within a string
1484-
// or not.
1481+
// This is a Go code block. The code needs to be evaluated, and the result written to the output.
1482+
// The variable is JSON encoded to ensure that it is safe to use within a script tag.
14851483
var r parser.Range
14861484
vn := g.createVariableName()
1487-
// var vn string
1488-
if _, err = g.w.WriteIndent(indentLevel, "var "+vn+" string\n"); err != nil {
1489-
return err
1485+
// Here, we need to get the result, which might be any type. We can use templ.ScriptContent to get the result.
1486+
// vn, templ_7745c5c3_Err := templruntime.ScriptContent(
1487+
fnCall := "templruntime.ScriptContentOutsideStringLiteral"
1488+
if c.InsideStringLiteral {
1489+
fnCall = "templruntime.ScriptContentInsideStringLiteral"
14901490
}
1491-
// Here, we need to get the result, which might be any type. We can use templ.JoinErrs to get the result.
1492-
// vn, templ_7745c5c3_Err = templruntime.JoinErrs(
1493-
if _, err = g.w.WriteIndent(indentLevel, vn+", templ_7745c5c3_Err = templruntime.JoinErrs("); err != nil {
1491+
if _, err = g.w.WriteIndent(indentLevel, vn+", templ_7745c5c3_Err := "+fnCall+"("); err != nil {
14941492
return err
14951493
}
14961494
// p.Name()
@@ -1509,42 +1507,22 @@ func (g *generator) writeScriptContents(indentLevel int, c parser.ScriptContents
15091507
return err
15101508
}
15111509

1512-
// Then, we need to JSON marshal it, and if the expression is within a string, we need to unquote it.
1513-
jvn := g.createVariableName()
1514-
// var jvn string
1515-
if _, err = g.w.WriteIndent(indentLevel, "var "+jvn+" string\n"); err != nil {
1516-
return err
1517-
}
1518-
// jvn, templ_7745c5c3_Err = json.Marshal(vn)
1519-
if _, err = g.w.WriteIndent(indentLevel, jvn+", templ_7745c3_Err = templ.JSONString("+vn+")\n"); err != nil {
1510+
// _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(jvn)
1511+
if _, err = g.w.WriteIndent(indentLevel, "_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("+vn+")\n"); err != nil {
15201512
return err
15211513
}
1522-
// Expression error handler.
1523-
err = g.writeExpressionErrorHandler(indentLevel, c.GoCode.Expression)
1524-
if err != nil {
1514+
if err = g.writeErrorHandler(indentLevel); err != nil {
15251515
return err
15261516
}
15271517

1528-
// If we're in a string, unquote the result.
1529-
if c.Quoted {
1530-
// jvn, templ_7745c5c3_Err = strconv.Unquote(jvn)
1531-
if _, err = g.w.WriteIndent(indentLevel, jvn+", templ_7745c3_Err = strconv.Unquote("+jvn+")\n"); err != nil {
1532-
return err
1533-
}
1534-
// Expression error handler.
1535-
err = g.writeExpressionErrorHandler(indentLevel, c.GoCode.Expression)
1536-
if err != nil {
1518+
// Write any trailing space.
1519+
if c.GoCode.TrailingSpace != "" {
1520+
if err = g.writeText(indentLevel, parser.Text{Value: string(c.GoCode.TrailingSpace)}); err != nil {
15371521
return err
15381522
}
15391523
}
15401524

1541-
// _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(jvn)
1542-
if _, err = g.w.WriteIndent(indentLevel, "_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString("+jvn+"))\n"); err != nil {
1543-
return err
1544-
}
1545-
if err = g.writeErrorHandler(indentLevel); err != nil {
1546-
return err
1547-
}
1525+
return nil
15481526
}
15491527
return errors.New("unknown script content")
15501528
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<h1>string data</h1>
2+
<script>
3+
var a = "hello";
4+
var b = "hello";
5+
var c = 'hello';
6+
var d = `hello`;
7+
</script>
8+
<script>
9+
console.log("hello")
10+
</script>
11+
<h1>string data with quotes</h1>
12+
<script>
13+
var a = "hello 'world'";
14+
var b = "hello 'world'";
15+
var c = 'hello "world"';
16+
var d = `hello 'world'`;
17+
</script>
18+
<script>
19+
console.log("hello 'world'")
20+
</script>
21+
<h1>numeric data</h1>
22+
<script>
23+
var a = 123
24+
var b = "123"
25+
var c = '123'
26+
var d = `123`
27+
</script>
28+
<script>
29+
console.log(123)
30+
</script>
31+
<h1>boolean data</h1>
32+
<script>
33+
var a = true
34+
var b = "true"
35+
var c = 'true'
36+
var d = `true`
37+
</script>
38+
<script>
39+
console.log(true)
40+
</script>
41+
<h1>array data</h1>
42+
<script>
43+
var a = [1, 2, 3]
44+
var b = "[1, 2, 3]"
45+
var c = '[1, 2, 3]'
46+
var d = `[1, 2, 3]`
47+
</script>
48+
<script>
49+
console.log([1, 2, 3])
50+
</script>
51+
<h1>object data</h1>
52+
<script>
53+
var a = { a: 1, b: 2, c: 3 }
54+
var b = "{ a: 1, b: 2, c: 3 }"
55+
var c = '{ a: 1, b: 2, c: 3 }'
56+
var d = `{ a: 1, b: 2, c: 3 }`
57+
</script>
58+
<script>
59+
console.log({ a: 1, b: 2, c: 3 })
60+
</script>
61+
<h1>null data</h1>
62+
<script>
63+
var a = null
64+
var b = "null"
65+
var c = 'null'
66+
var d = `null`
67+
</script>
68+
<script>
69+
console.log(null)
70+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package testscriptexpressions
2+
3+
import (
4+
_ "embed"
5+
"testing"
6+
7+
"github.com/a-h/templ/generator/htmldiff"
8+
)
9+
10+
//go:embed expected.html
11+
var expected string
12+
13+
func Test(t *testing.T) {
14+
component := AllTests()
15+
16+
diff, err := htmldiff.Diff(component, expected)
17+
if err != nil {
18+
t.Fatal(err)
19+
}
20+
if diff != "" {
21+
t.Error(diff)
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package testscriptexpressions
2+
3+
templ Script[T any](name string, data T) {
4+
<h1>{ name }</h1>
5+
<script>
6+
var a = {{ data }}
7+
var b = "{{ data }}"
8+
var c = '{{ data }}'
9+
var d = `{{ data }}`
10+
</script>
11+
<script>
12+
console.log({{ data }})
13+
</script>
14+
}
15+
16+
templ AllTests() {
17+
@Script("string data", "hello")
18+
@Script("string data with quotes", "hello 'world'")
19+
@Script("numeric data", 123)
20+
@Script("boolean data", true)
21+
@Script("array data", []int{1, 2, 3})
22+
@Script("object data", struct {
23+
Name string
24+
Age int
25+
}{"Alice", 30})
26+
@Script[*string]("null data", nil)
27+
}

generator/test-script-expressions/template_templ.go

+168
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

parser/v2/expressionparser.go

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ var openBraceWithOptionalPadding = parse.Any(openBraceWithPadding, openBrace)
3939
var closeBrace = parse.String("}")
4040
var closeBraceWithOptionalPadding = parse.StringFrom(optionalSpaces, closeBrace)
4141

42+
var dblOpenBrace = parse.String("{{")
43+
var dblOpenBraceWithOptionalPadding = parse.StringFrom(dblOpenBrace, optionalSpaces)
44+
4245
var dblCloseBrace = parse.String("}}")
4346
var dblCloseBraceWithOptionalPadding = parse.StringFrom(optionalSpaces, dblCloseBrace)
4447

0 commit comments

Comments
 (0)