Skip to content

Commit 43504b5

Browse files
committed
fix: ensure string escaping is correct inside javascript strings
1 parent 02ed092 commit 43504b5

File tree

7 files changed

+81
-62
lines changed

7 files changed

+81
-62
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
<div
2-
x-data="{darkMode: localStorage.getItem('darkMode') || localStorage.setItem('darkMode', 'system')}"
3-
x-init="$watch('darkMode', val => localStorage.setItem('darkMode', val))"
4-
:class="{'dark': darkMode === 'dark' || (darkMode === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)}"
5-
>
6-
</div>
2+
x-data="{darkMode: localStorage.getItem('darkMode') || localStorage.setItem('darkMode', 'system')}"
3+
x-init="$watch('darkMode', val => localStorage.setItem('darkMode', val))"
4+
:class="{'dark': darkMode === 'dark' || (darkMode === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)}"
5+
></div>
76
<div x-data="{ count: 0 }">
8-
<button
9-
x-on:click="count++"
10-
>Increment</button>
11-
<span x-text="count"></span>
7+
<button
8+
x-on:click="count++"
9+
>Increment</button>
10+
<span x-text="count"></span>
1211
</div>
1312
<div x-data="{ count: 0 }">
14-
<button
15-
@click="count++"
16-
>Increment</button>
17-
<span x-text="count"></span>
13+
<button
14+
@click="count++"
15+
>Increment</button>
16+
<span x-text="count"></span>
1817
</div>

generator/test-element-attributes/expected.html

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
</div>
1616
<div data-script="on click
1717
do something
18-
end">
19-
</div>
18+
end"></div>
2019

2120
<h2>HTMX Wildcard attribute</h2>
2221

Original file line numberDiff line numberDiff line change
@@ -1,70 +1,70 @@
11
<h1>string data</h1>
22
<script>
3-
var a = "hello";
4-
var b = "hello";
5-
var c = 'hello';
6-
var d = `hello`;
3+
var a = "hello"
4+
var b = "hello"
5+
var c = 'hello'
6+
var d = `hello`
77
</script>
88
<script>
9-
console.log("hello")
9+
console.log("hello")
1010
</script>
1111
<h1>string data with quotes</h1>
1212
<script>
13-
var a = "hello 'world'";
14-
var b = "hello 'world'";
15-
var c = 'hello "world"';
16-
var d = `hello 'world'`;
13+
var a = "hello 'world'"
14+
var b = "hello \'world\'"
15+
var c = 'hello \'world\''
16+
var d = `hello \'world\'`
1717
</script>
1818
<script>
19-
console.log("hello 'world'")
19+
console.log("hello 'world'")
2020
</script>
2121
<h1>numeric data</h1>
2222
<script>
23-
var a = 123
24-
var b = "123"
25-
var c = '123'
26-
var d = `123`
23+
var a = 123
24+
var b = "123"
25+
var c = '123'
26+
var d = `123`
2727
</script>
2828
<script>
29-
console.log(123)
29+
console.log(123)
3030
</script>
3131
<h1>boolean data</h1>
3232
<script>
33-
var a = true
34-
var b = "true"
35-
var c = 'true'
36-
var d = `true`
33+
var a = true
34+
var b = "true"
35+
var c = 'true'
36+
var d = `true`
3737
</script>
3838
<script>
39-
console.log(true)
39+
console.log(true)
4040
</script>
4141
<h1>array data</h1>
4242
<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]`
43+
var a = [1,2,3]
44+
var b = "[1,2,3]"
45+
var c = '[1,2,3]'
46+
var d = `[1,2,3]`
4747
</script>
4848
<script>
49-
console.log([1, 2, 3])
49+
console.log([1,2,3])
5050
</script>
5151
<h1>object data</h1>
5252
<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 }`
53+
var a = {"Name":"Alice","Age":30}
54+
var b = "{\"Name\":\"Alice\",\"Age\":30}"
55+
var c = '{\"Name\":\"Alice\",\"Age\":30}'
56+
var d = `{\"Name\":\"Alice\",\"Age\":30}`
5757
</script>
5858
<script>
59-
console.log({ a: 1, b: 2, c: 3 })
59+
console.log({"Name":"Alice","Age":30})
6060
</script>
6161
<h1>null data</h1>
6262
<script>
63-
var a = null
64-
var b = "null"
65-
var c = 'null'
66-
var d = `null`
63+
var a = null
64+
var b = "null"
65+
var c = 'null'
66+
var d = `null`
6767
</script>
6868
<script>
69-
console.log(null)
69+
console.log(null)
7070
</script>

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.23
55
toolchain go1.23.3
66

77
require (
8-
github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e
8+
github.com/a-h/htmlformat v0.0.0-20250209131833-673be874c677
99
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e
1010
github.com/andybalholm/brotli v1.1.0
1111
github.com/cenkalti/backoff/v4 v4.3.0
@@ -16,15 +16,15 @@ require (
1616
github.com/natefinch/atomic v1.0.1
1717
github.com/rs/cors v1.11.0
1818
golang.org/x/mod v0.20.0
19-
golang.org/x/net v0.33.0
19+
golang.org/x/net v0.34.0
2020
golang.org/x/sync v0.10.0
2121
golang.org/x/tools v0.24.0
2222
)
2323

2424
require (
2525
github.com/mattn/go-colorable v0.1.13 // indirect
2626
github.com/mattn/go-isatty v0.0.20 // indirect
27-
golang.org/x/sys v0.28.0 // indirect
27+
golang.org/x/sys v0.29.0 // indirect
2828
)
2929

3030
// replace github.com/a-h/parse => /Users/adrian/github.com/a-h/parse

go.sum

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e h1:Eog54DQpku7NpPNff9wzQYT61TGu9jjq5N8UhAkqIgw=
2-
github.com/a-h/htmlformat v0.0.0-20231108124658-5bd994fe268e/go.mod h1:FMIm5afKmEfarNbIXOaPHFY8X7fo+fRQB6I9MPG2nB0=
1+
github.com/a-h/htmlformat v0.0.0-20250209131833-673be874c677 h1:H1EoxMpNo/TnCZEgSaKsomi+dQ05dXiVSKDN86Lap9A=
2+
github.com/a-h/htmlformat v0.0.0-20250209131833-673be874c677/go.mod h1:FMIm5afKmEfarNbIXOaPHFY8X7fo+fRQB6I9MPG2nB0=
33
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo=
44
github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ=
55
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
@@ -25,13 +25,13 @@ github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
2525
github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
2626
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
2727
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
28-
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
29-
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
28+
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
29+
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
3030
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
3131
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
3232
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3333
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
34-
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
35-
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
34+
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
35+
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3636
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
3737
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=

runtime/scriptelement.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package runtime
33
import (
44
"encoding/json"
55
"errors"
6-
"strings"
6+
"html/template"
77
)
88

99
func ScriptContentInsideStringLiteral[T any](v T, errs ...error) (string, error) {
@@ -18,12 +18,15 @@ func scriptContent[T any](v T, insideStringLiteral bool, errs ...error) (string,
1818
if errors.Join(errs...) != nil {
1919
return "", errors.Join(errs...)
2020
}
21+
if vs, ok := any(v).(string); ok && insideStringLiteral {
22+
return template.JSEscapeString(vs), nil
23+
}
2124
jd, err := json.Marshal(v)
2225
if err != nil {
2326
return "", err
2427
}
2528
if insideStringLiteral {
26-
return strings.Trim(string(jd), "\""), nil
29+
return template.JSEscapeString(string(jd)), nil
2730
}
2831
return string(jd), nil
2932
}

runtime/scriptelement_test.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ func TestScriptContent(t *testing.T) {
1818
expectedInsideStringLiteral: `hello`,
1919
expectedOutsideStringLiteral: `"hello"`,
2020
},
21+
{
22+
name: "string with single quotes",
23+
input: "hello 'world'",
24+
expectedInsideStringLiteral: `hello \'world\'`,
25+
expectedOutsideStringLiteral: `"hello 'world'"`,
26+
},
27+
{
28+
name: "string with double quotes",
29+
input: "hello \"world\"",
30+
expectedInsideStringLiteral: `hello \"world\"`,
31+
expectedOutsideStringLiteral: `"hello \"world\""`,
32+
},
33+
{
34+
name: "string with backticks",
35+
input: "hello `world`",
36+
expectedInsideStringLiteral: "hello `world`",
37+
expectedOutsideStringLiteral: "\"hello `world`\"",
38+
},
2139
{
2240
name: "int",
2341
input: 1,
@@ -45,7 +63,7 @@ func TestScriptContent(t *testing.T) {
4563
{
4664
name: "object",
4765
input: struct{ Name string }{"Alice"},
48-
expectedInsideStringLiteral: `{"Name":"Alice"}`,
66+
expectedInsideStringLiteral: `{\"Name\":\"Alice\"}`,
4967
expectedOutsideStringLiteral: `{"Name":"Alice"}`,
5068
},
5169
}

0 commit comments

Comments
 (0)