gofront 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/package.json +5 -4
- package/src/backend/js/expressions.js +849 -371
- package/src/backend/js/index.js +241 -147
- package/src/backend/js/natives.js +383 -0
- package/src/backend/js/runtime.js +512 -2547
- package/src/backend/js/statements.js +506 -103
- package/src/backend/js/stdlib/index.js +45 -93
- package/src/backend/js/templ.js +32 -45
- package/src/backend/js/type-info.js +177 -13
- package/src/backend/shared/fixed-float.js +20 -0
- package/src/backend/shared/fmt-types.js +63 -171
- package/src/backend/shared/host-unicode.js +36 -0
- package/src/backend/wasm/boundary.js +490 -965
- package/src/backend/wasm/emit-builtins.js +643 -256
- package/src/backend/wasm/emit-exprs.js +124 -57
- package/src/backend/wasm/emit-maps.js +17 -367
- package/src/backend/wasm/emit-stmts.js +325 -75
- package/src/backend/wasm/emit.js +104 -13
- package/src/backend/wasm/globals.js +47 -8
- package/src/backend/wasm/glue.js +2 -4
- package/src/backend/wasm/index.js +36 -530
- package/src/backend/wasm/method-expr.js +12 -1
- package/src/backend/wasm/module-emitter.js +92 -717
- package/src/backend/wasm/monomorph.js +103 -6
- package/src/backend/wasm/natives.js +596 -0
- package/src/backend/wasm/prescan.js +5 -153
- package/src/backend/wasm/prune-funcs.js +89 -0
- package/src/backend/wasm/stdlib/index.js +2 -32
- package/src/backend/wasm/types.js +68 -20
- package/src/backend/wasm/variadic.js +3 -3
- package/src/cli/cli-core.js +5 -1
- package/src/cli/test-runner.js +115 -342
- package/src/compiler.js +108 -130
- package/src/lexer/lexer.js +105 -11
- package/src/lexer/templ-lexer.js +61 -18
- package/src/lexer/tokens.js +1 -0
- package/src/link/stdlib.js +354 -132
- package/src/link/type-names.js +148 -0
- package/src/link/wasm.js +30 -6
- package/src/lower/bounds.js +153 -0
- package/src/lower/captures.js +92 -33
- package/src/lower/embedding.js +32 -3
- package/src/lower/errors-as.js +196 -0
- package/src/lower/fmt-formatters.js +905 -0
- package/src/lower/functions.js +2 -0
- package/src/lower/gen-types.js +274 -0
- package/src/lower/index.js +7 -1
- package/src/lower/json-codecs.js +228 -247
- package/src/lower/ownership.js +25 -7
- package/src/lower/reachability.js +69 -51
- package/src/lower/walk.js +12 -0
- package/src/parser/declarations.js +28 -5
- package/src/parser/expressions.js +86 -16
- package/src/parser/statements.js +1 -0
- package/src/parser/templ.js +44 -5
- package/src/parser/types.js +1 -0
- package/src/resolver.js +1 -2
- package/src/typechecker/assignability.js +124 -11
- package/src/typechecker/const-fold.js +70 -27
- package/src/typechecker/constants.js +32 -6
- package/src/typechecker/expressions.js +326 -98
- package/src/typechecker/index.js +208 -33
- package/src/typechecker/init-order.js +136 -40
- package/src/typechecker/operand-text.js +40 -0
- package/src/typechecker/resolve.js +192 -36
- package/src/typechecker/statements.js +122 -11
- package/src/typechecker/stdlib/excluded.js +9 -5
- package/src/typechecker/stdlib/index.js +25 -9
- package/src/typechecker/termination.js +10 -1
- package/src/typechecker/types.js +203 -573
- package/stdlib/bytes/buffer.go +479 -0
- package/stdlib/bytes/bytes.go +1010 -0
- package/stdlib/bytes/reader.go +161 -0
- package/stdlib/context/context.go +115 -0
- package/stdlib/crypto/rand/rand.go +34 -0
- package/stdlib/crypto/sha256/sha256.go +249 -0
- package/stdlib/encoding/base64/base64.go +331 -0
- package/stdlib/encoding/binary/binary.go +332 -0
- package/stdlib/encoding/hex/hex.go +140 -0
- package/stdlib/encoding/json/json.go +62 -0
- package/stdlib/errors/errors.go +174 -0
- package/stdlib/fmt/errors.go +110 -0
- package/stdlib/fmt/format.go +732 -0
- package/stdlib/fmt/print.go +1232 -0
- package/stdlib/gom/gom.go +293 -0
- package/stdlib/html/html.go +251 -0
- package/stdlib/internal/fmtrt/fmtrt.go +163 -0
- package/stdlib/internal/jsonrt/dec.go +171 -38
- package/stdlib/internal/jsonrt/enc.go +186 -36
- package/stdlib/internal/jsonrt/scanner.go +17 -8
- package/stdlib/io/io.go +157 -1
- package/stdlib/maps/maps.go +131 -0
- package/stdlib/math/bits/bits.go +507 -0
- package/stdlib/math/extra.go +16 -14
- package/stdlib/math/math.go +439 -0
- package/stdlib/math/rand/rand.go +297 -0
- package/stdlib/os/os.go +93 -0
- package/stdlib/path/filepath/filepath.go +47 -0
- package/stdlib/path/path.go +394 -0
- package/stdlib/regexp/regexp.go +231 -0
- package/stdlib/slices/slices.go +526 -0
- package/stdlib/slices/sort.go +209 -0
- package/stdlib/slices/zsort_cmp.go +480 -0
- package/stdlib/slices/zsort_ordered.go +482 -0
- package/stdlib/sort/sort.go +391 -452
- package/stdlib/sort/zsort_func.go +480 -0
- package/stdlib/sort/zsort_iface.go +480 -0
- package/stdlib/strconv/float.go +1699 -0
- package/stdlib/strconv/isprint.go +752 -0
- package/stdlib/strconv/quote.go +235 -50
- package/stdlib/strconv/strconv.go +616 -0
- package/stdlib/strings/builder.go +95 -0
- package/stdlib/strings/reader.go +163 -0
- package/stdlib/strings/replacer.go +102 -0
- package/stdlib/strings/strings.go +807 -0
- package/stdlib/sync/sync.go +268 -0
- package/stdlib/testing/async_js.go +61 -0
- package/stdlib/testing/benchmark.go +297 -0
- package/stdlib/testing/testing.go +523 -0
- package/stdlib/time/duration.go +233 -0
- package/stdlib/time/format.go +745 -0
- package/stdlib/time/parse.go +790 -0
- package/stdlib/time/sleep_js.go +63 -0
- package/stdlib/time/time.go +834 -0
- package/stdlib/unicode/unicode.go +141 -3
- package/stdlib/unicode/utf8/utf8.go +464 -0
- package/src/backend/js/fmt-runtime.js +0 -573
- package/src/backend/js/stdlib/base64.js +0 -12
- package/src/backend/js/stdlib/binary.js +0 -102
- package/src/backend/js/stdlib/bits.js +0 -119
- package/src/backend/js/stdlib/builder.js +0 -98
- package/src/backend/js/stdlib/bytes.js +0 -368
- package/src/backend/js/stdlib/errors.js +0 -45
- package/src/backend/js/stdlib/fmt.js +0 -517
- package/src/backend/js/stdlib/gom.js +0 -155
- package/src/backend/js/stdlib/hex.js +0 -17
- package/src/backend/js/stdlib/html.js +0 -20
- package/src/backend/js/stdlib/io.js +0 -137
- package/src/backend/js/stdlib/json.js +0 -1167
- package/src/backend/js/stdlib/maps.js +0 -37
- package/src/backend/js/stdlib/math.js +0 -85
- package/src/backend/js/stdlib/os.js +0 -13
- package/src/backend/js/stdlib/path.js +0 -48
- package/src/backend/js/stdlib/rand.js +0 -32
- package/src/backend/js/stdlib/regexp.js +0 -54
- package/src/backend/js/stdlib/sha256.js +0 -12
- package/src/backend/js/stdlib/shared.js +0 -17
- package/src/backend/js/stdlib/simd.js +0 -34
- package/src/backend/js/stdlib/slices.js +0 -107
- package/src/backend/js/stdlib/sort.js +0 -30
- package/src/backend/js/stdlib/strconv.js +0 -79
- package/src/backend/js/stdlib/strings.js +0 -301
- package/src/backend/js/stdlib/sync.js +0 -13
- package/src/backend/js/stdlib/testing.js +0 -41
- package/src/backend/js/stdlib/time.js +0 -152
- package/src/backend/js/stdlib/unicode.js +0 -25
- package/src/backend/js/stdlib/utf8.js +0 -26
- package/src/backend/wasm/stdlib/bytes.js +0 -6716
- package/src/backend/wasm/stdlib/core.js +0 -10278
- package/src/backend/wasm/stdlib/io.js +0 -3578
- package/src/backend/wasm/stdlib/packages.js +0 -2402
- package/src/backend/wasm/stdlib/pure.js +0 -720
- package/src/backend/wasm/stdlib/time.js +0 -2229
- package/src/typechecker/stdlib/core.js +0 -1079
- package/src/typechecker/stdlib/extended.js +0 -1210
- package/stdlib/bytes/iter.go +0 -192
- package/stdlib/bytes/search.go +0 -240
- package/stdlib/bytes/split.go +0 -218
- package/stdlib/errors/overlay.go +0 -12
- package/stdlib/maps/iter.go +0 -65
- package/stdlib/slices/extra.go +0 -73
- package/stdlib/slices/iter.go +0 -113
- package/stdlib/strings/extra.go +0 -35
- package/stdlib/strings/iter.go +0 -122
- package/stdlib/sync/extra.go +0 -105
- package/stdlib/unicode/utf8/bytes.go +0 -239
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target js
|
|
4
|
+
|
|
5
|
+
// Package gom builds DOM trees from Go values. A Node mounts itself into a
|
|
6
|
+
// parent element; templ components are Nodes too. It is only available to js
|
|
7
|
+
// packages and needs no import.
|
|
8
|
+
package gom
|
|
9
|
+
|
|
10
|
+
// A Node adds itself to the DOM element parent. refs, when not nil, is the
|
|
11
|
+
// map that `ref="key"` attributes of templ components fill with elements.
|
|
12
|
+
type Node interface {
|
|
13
|
+
Mount(parent any, refs any)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// NodeFunc adapts a function that mounts into an element to a Node.
|
|
17
|
+
type NodeFunc func(parent any)
|
|
18
|
+
|
|
19
|
+
func (f NodeFunc) Mount(parent any, refs any) {
|
|
20
|
+
f(parent)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Group mounts its nodes one after another into the same parent.
|
|
24
|
+
type Group []Node
|
|
25
|
+
|
|
26
|
+
func (g Group) Mount(parent any, refs any) {
|
|
27
|
+
for _, n := range g {
|
|
28
|
+
if n != nil {
|
|
29
|
+
n.Mount(parent, refs)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type element struct {
|
|
35
|
+
tag string
|
|
36
|
+
children []Node
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func (e *element) Mount(parent any, refs any) {
|
|
40
|
+
el := document.createElement(e.tag)
|
|
41
|
+
for _, c := range e.children {
|
|
42
|
+
if c != nil {
|
|
43
|
+
c.Mount(el, refs)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
parent.appendChild(el)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type text struct{ s string }
|
|
50
|
+
|
|
51
|
+
func (t *text) Mount(parent any, refs any) {
|
|
52
|
+
parent.appendChild(document.createTextNode(t.s))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type attr struct{ name, value string }
|
|
56
|
+
|
|
57
|
+
func (a *attr) Mount(el any, refs any) {
|
|
58
|
+
el.setAttribute(a.name, a.value)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type prop struct{ name, value string }
|
|
62
|
+
|
|
63
|
+
func (p *prop) Mount(el any, refs any) {
|
|
64
|
+
el[p.name] = p.value
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
type style struct{ css string }
|
|
68
|
+
|
|
69
|
+
func (s *style) Mount(parent any, refs any) {
|
|
70
|
+
el := document.createElement("style")
|
|
71
|
+
el.textContent = s.css
|
|
72
|
+
parent.appendChild(el)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// El is an element with the given tag, attributes and children.
|
|
76
|
+
func El(tag string, children ...Node) Node {
|
|
77
|
+
return &element{tag: tag, children: children}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Text is a text node.
|
|
81
|
+
func Text(s string) Node {
|
|
82
|
+
return &text{s: s}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Attr sets an attribute.
|
|
86
|
+
func Attr(name, value string) Node {
|
|
87
|
+
return &attr{name: name, value: value}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// DataAttr sets the attribute data-<key>.
|
|
91
|
+
func DataAttr(key, value string) Node {
|
|
92
|
+
return &attr{name: "data-" + key, value: value}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// If is n when cond holds, and an empty node otherwise.
|
|
96
|
+
func If(cond bool, n Node) Node {
|
|
97
|
+
if cond {
|
|
98
|
+
return n
|
|
99
|
+
}
|
|
100
|
+
return Group{}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Map applies f to every element of s; the nodes mount in order.
|
|
104
|
+
func Map[T any](s []T, f func(T) Node) Node {
|
|
105
|
+
g := make(Group, 0, len(s))
|
|
106
|
+
for _, v := range s {
|
|
107
|
+
g = append(g, f(v))
|
|
108
|
+
}
|
|
109
|
+
return g
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Style is a <style> element with the given CSS text.
|
|
113
|
+
func Style(css string) Node {
|
|
114
|
+
return &style{css: css}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
func refOf(refs []any) any {
|
|
118
|
+
if len(refs) > 0 {
|
|
119
|
+
return refs[0]
|
|
120
|
+
}
|
|
121
|
+
return nil
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Mount replaces the content of the element matching the selector with node.
|
|
125
|
+
// The optional refs map receives the elements of templ `ref` attributes.
|
|
126
|
+
func Mount(sel string, node Node, refs ...any) {
|
|
127
|
+
el := document.querySelector(sel)
|
|
128
|
+
el.innerHTML = ""
|
|
129
|
+
node.Mount(el, refOf(refs))
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// MountTo is like Mount but keeps the existing content.
|
|
133
|
+
func MountTo(sel string, node Node, refs ...any) {
|
|
134
|
+
node.Mount(document.querySelector(sel), refOf(refs))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Elements.
|
|
138
|
+
|
|
139
|
+
func Div(children ...Node) Node { return El("div", children...) }
|
|
140
|
+
|
|
141
|
+
func Section(children ...Node) Node { return El("section", children...) }
|
|
142
|
+
|
|
143
|
+
func Article(children ...Node) Node { return El("article", children...) }
|
|
144
|
+
|
|
145
|
+
func Aside(children ...Node) Node { return El("aside", children...) }
|
|
146
|
+
|
|
147
|
+
func Header(children ...Node) Node { return El("header", children...) }
|
|
148
|
+
|
|
149
|
+
func Footer(children ...Node) Node { return El("footer", children...) }
|
|
150
|
+
|
|
151
|
+
func Main(children ...Node) Node { return El("main", children...) }
|
|
152
|
+
|
|
153
|
+
func Nav(children ...Node) Node { return El("nav", children...) }
|
|
154
|
+
|
|
155
|
+
func Figure(children ...Node) Node { return El("figure", children...) }
|
|
156
|
+
|
|
157
|
+
func H1(children ...Node) Node { return El("h1", children...) }
|
|
158
|
+
|
|
159
|
+
func H2(children ...Node) Node { return El("h2", children...) }
|
|
160
|
+
|
|
161
|
+
func H3(children ...Node) Node { return El("h3", children...) }
|
|
162
|
+
|
|
163
|
+
func H4(children ...Node) Node { return El("h4", children...) }
|
|
164
|
+
|
|
165
|
+
func H5(children ...Node) Node { return El("h5", children...) }
|
|
166
|
+
|
|
167
|
+
func H6(children ...Node) Node { return El("h6", children...) }
|
|
168
|
+
|
|
169
|
+
func Span(children ...Node) Node { return El("span", children...) }
|
|
170
|
+
|
|
171
|
+
func A(children ...Node) Node { return El("a", children...) }
|
|
172
|
+
|
|
173
|
+
func Strong(children ...Node) Node { return El("strong", children...) }
|
|
174
|
+
|
|
175
|
+
func Em(children ...Node) Node { return El("em", children...) }
|
|
176
|
+
|
|
177
|
+
func Code(children ...Node) Node { return El("code", children...) }
|
|
178
|
+
|
|
179
|
+
func Pre(children ...Node) Node { return El("pre", children...) }
|
|
180
|
+
|
|
181
|
+
func Small(children ...Node) Node { return El("small", children...) }
|
|
182
|
+
|
|
183
|
+
func Mark(children ...Node) Node { return El("mark", children...) }
|
|
184
|
+
|
|
185
|
+
func P(children ...Node) Node { return El("p", children...) }
|
|
186
|
+
|
|
187
|
+
func Br(children ...Node) Node { return El("br", children...) }
|
|
188
|
+
|
|
189
|
+
func Hr(children ...Node) Node { return El("hr", children...) }
|
|
190
|
+
|
|
191
|
+
func Ul(children ...Node) Node { return El("ul", children...) }
|
|
192
|
+
|
|
193
|
+
func Ol(children ...Node) Node { return El("ol", children...) }
|
|
194
|
+
|
|
195
|
+
func Li(children ...Node) Node { return El("li", children...) }
|
|
196
|
+
|
|
197
|
+
func Dl(children ...Node) Node { return El("dl", children...) }
|
|
198
|
+
|
|
199
|
+
func Dt(children ...Node) Node { return El("dt", children...) }
|
|
200
|
+
|
|
201
|
+
func Dd(children ...Node) Node { return El("dd", children...) }
|
|
202
|
+
|
|
203
|
+
func Form(children ...Node) Node { return El("form", children...) }
|
|
204
|
+
|
|
205
|
+
func Input(children ...Node) Node { return El("input", children...) }
|
|
206
|
+
|
|
207
|
+
func Button(children ...Node) Node { return El("button", children...) }
|
|
208
|
+
|
|
209
|
+
func Textarea(children ...Node) Node { return El("textarea", children...) }
|
|
210
|
+
|
|
211
|
+
func Select(children ...Node) Node { return El("select", children...) }
|
|
212
|
+
|
|
213
|
+
func Option(children ...Node) Node { return El("option", children...) }
|
|
214
|
+
|
|
215
|
+
func Label(children ...Node) Node { return El("label", children...) }
|
|
216
|
+
|
|
217
|
+
func Fieldset(children ...Node) Node { return El("fieldset", children...) }
|
|
218
|
+
|
|
219
|
+
func Legend(children ...Node) Node { return El("legend", children...) }
|
|
220
|
+
|
|
221
|
+
func Img(children ...Node) Node { return El("img", children...) }
|
|
222
|
+
|
|
223
|
+
func Video(children ...Node) Node { return El("video", children...) }
|
|
224
|
+
|
|
225
|
+
func Audio(children ...Node) Node { return El("audio", children...) }
|
|
226
|
+
|
|
227
|
+
func Canvas(children ...Node) Node { return El("canvas", children...) }
|
|
228
|
+
|
|
229
|
+
func Table(children ...Node) Node { return El("table", children...) }
|
|
230
|
+
|
|
231
|
+
func Thead(children ...Node) Node { return El("thead", children...) }
|
|
232
|
+
|
|
233
|
+
func Tbody(children ...Node) Node { return El("tbody", children...) }
|
|
234
|
+
|
|
235
|
+
func Tfoot(children ...Node) Node { return El("tfoot", children...) }
|
|
236
|
+
|
|
237
|
+
func Tr(children ...Node) Node { return El("tr", children...) }
|
|
238
|
+
|
|
239
|
+
func Th(children ...Node) Node { return El("th", children...) }
|
|
240
|
+
|
|
241
|
+
func Td(children ...Node) Node { return El("td", children...) }
|
|
242
|
+
|
|
243
|
+
// Attributes.
|
|
244
|
+
|
|
245
|
+
func For(v string) Node { return Attr("for", v) }
|
|
246
|
+
|
|
247
|
+
func Name(v string) Node { return Attr("name", v) }
|
|
248
|
+
|
|
249
|
+
func Value(v string) Node { return Attr("value", v) }
|
|
250
|
+
|
|
251
|
+
func Target(v string) Node { return Attr("target", v) }
|
|
252
|
+
|
|
253
|
+
func Rel(v string) Node { return Attr("rel", v) }
|
|
254
|
+
|
|
255
|
+
func Alt(v string) Node { return Attr("alt", v) }
|
|
256
|
+
|
|
257
|
+
func Title(v string) Node { return Attr("title", v) }
|
|
258
|
+
|
|
259
|
+
func Lang(v string) Node { return Attr("lang", v) }
|
|
260
|
+
|
|
261
|
+
func Action(v string) Node { return Attr("action", v) }
|
|
262
|
+
|
|
263
|
+
func Method(v string) Node { return Attr("method", v) }
|
|
264
|
+
|
|
265
|
+
func AutoComplete(v string) Node { return Attr("autocomplete", v) }
|
|
266
|
+
|
|
267
|
+
func Draggable(v string) Node { return Attr("draggable", v) }
|
|
268
|
+
|
|
269
|
+
func Role(v string) Node { return Attr("role", v) }
|
|
270
|
+
|
|
271
|
+
func StyleAttr(v string) Node { return Attr("style", v) }
|
|
272
|
+
|
|
273
|
+
func AriaLabel(v string) Node { return Attr("aria-label", v) }
|
|
274
|
+
|
|
275
|
+
func Disabled() Node { return Attr("disabled", "") }
|
|
276
|
+
|
|
277
|
+
func Checked() Node { return Attr("checked", "") }
|
|
278
|
+
|
|
279
|
+
func Selected() Node { return Attr("selected", "") }
|
|
280
|
+
|
|
281
|
+
func Readonly() Node { return Attr("readonly", "") }
|
|
282
|
+
|
|
283
|
+
// Properties.
|
|
284
|
+
|
|
285
|
+
func Class(v string) Node { return &prop{name: "className", value: v} }
|
|
286
|
+
|
|
287
|
+
func Type(v string) Node { return &prop{name: "type", value: v} }
|
|
288
|
+
|
|
289
|
+
func Href(v string) Node { return &prop{name: "href", value: v} }
|
|
290
|
+
|
|
291
|
+
func Src(v string) Node { return &prop{name: "src", value: v} }
|
|
292
|
+
|
|
293
|
+
func Placeholder(v string) Node { return &prop{name: "placeholder", value: v} }
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
// Copyright 2010 The Go Authors. All rights reserved.
|
|
6
|
+
// Use of this source code is governed by a BSD-style
|
|
7
|
+
// license that can be found in the LICENSE file.
|
|
8
|
+
|
|
9
|
+
// Package html provides functions for escaping and unescaping HTML text.
|
|
10
|
+
//
|
|
11
|
+
// UnescapeString follows Go's algorithm for numeric references (including the
|
|
12
|
+
// Windows-1252 replacement table) and for named references without a
|
|
13
|
+
// semicolon, but knows a subset of Go's 2,231 entity names: the five that
|
|
14
|
+
// EscapeString produces and apos, the 96 HTML 4 Latin-1 names (nbsp through
|
|
15
|
+
// yuml) and these others: euro, hellip, mdash, ndash, lsquo, rsquo, sbquo,
|
|
16
|
+
// ldquo, rdquo, bdquo, bull, trade, larr, rarr, uarr, darr, harr, hearts,
|
|
17
|
+
// spades, clubs and diams. An unknown name is left as it is.
|
|
18
|
+
package html
|
|
19
|
+
|
|
20
|
+
var replacementTable = [...]rune{
|
|
21
|
+
'\u20AC', // First entry is what 0x80 should be replaced with.
|
|
22
|
+
'\u0081',
|
|
23
|
+
'\u201A',
|
|
24
|
+
'\u0192',
|
|
25
|
+
'\u201E',
|
|
26
|
+
'\u2026',
|
|
27
|
+
'\u2020',
|
|
28
|
+
'\u2021',
|
|
29
|
+
'\u02C6',
|
|
30
|
+
'\u2030',
|
|
31
|
+
'\u0160',
|
|
32
|
+
'\u2039',
|
|
33
|
+
'\u0152',
|
|
34
|
+
'\u008D',
|
|
35
|
+
'\u017D',
|
|
36
|
+
'\u008F',
|
|
37
|
+
'\u0090',
|
|
38
|
+
'\u2018',
|
|
39
|
+
'\u2019',
|
|
40
|
+
'\u201C',
|
|
41
|
+
'\u201D',
|
|
42
|
+
'\u2022',
|
|
43
|
+
'\u2013',
|
|
44
|
+
'\u2014',
|
|
45
|
+
'\u02DC',
|
|
46
|
+
'\u2122',
|
|
47
|
+
'\u0161',
|
|
48
|
+
'\u203A',
|
|
49
|
+
'\u0153',
|
|
50
|
+
'\u009D',
|
|
51
|
+
'\u017E',
|
|
52
|
+
'\u0178', // Last entry is 0x9F.
|
|
53
|
+
// 0x00->'\uFFFD' is handled programmatically.
|
|
54
|
+
// 0x0D->'\u000D' is a no-op.
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// latin1 holds the HTML 4 names of the runes U+00A0 through U+00FF, in order.
|
|
58
|
+
var latin1 = [...]string{
|
|
59
|
+
"nbsp", "iexcl", "cent", "pound", "curren", "yen", "brvbar", "sect",
|
|
60
|
+
"uml", "copy", "ordf", "laquo", "not", "shy", "reg", "macr",
|
|
61
|
+
"deg", "plusmn", "sup2", "sup3", "acute", "micro", "para", "middot",
|
|
62
|
+
"cedil", "sup1", "ordm", "raquo", "frac14", "frac12", "frac34", "iquest",
|
|
63
|
+
"Agrave", "Aacute", "Acirc", "Atilde", "Auml", "Aring", "AElig", "Ccedil",
|
|
64
|
+
"Egrave", "Eacute", "Ecirc", "Euml", "Igrave", "Iacute", "Icirc", "Iuml",
|
|
65
|
+
"ETH", "Ntilde", "Ograve", "Oacute", "Ocirc", "Otilde", "Ouml", "times",
|
|
66
|
+
"Oslash", "Ugrave", "Uacute", "Ucirc", "Uuml", "Yacute", "THORN", "szlig",
|
|
67
|
+
"agrave", "aacute", "acirc", "atilde", "auml", "aring", "aelig", "ccedil",
|
|
68
|
+
"egrave", "eacute", "ecirc", "euml", "igrave", "iacute", "icirc", "iuml",
|
|
69
|
+
"eth", "ntilde", "ograve", "oacute", "ocirc", "otilde", "ouml", "divide",
|
|
70
|
+
"oslash", "ugrave", "uacute", "ucirc", "uuml", "yacute", "thorn", "yuml",
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// longestEntityWithoutSemicolon is the length of the longest name that may
|
|
74
|
+
// appear without its closing semicolon.
|
|
75
|
+
const longestEntityWithoutSemicolon = 6
|
|
76
|
+
|
|
77
|
+
// entities is the entity table: every name with its semicolon, and the
|
|
78
|
+
// legacy names (the Latin-1 ones, amp, lt, gt and quot) without it too.
|
|
79
|
+
var entities = makeEntities()
|
|
80
|
+
|
|
81
|
+
func makeEntities() map[string]rune {
|
|
82
|
+
m := make(map[string]rune)
|
|
83
|
+
for i, name := range latin1 {
|
|
84
|
+
m[name+";"] = rune(0xA0 + i)
|
|
85
|
+
m[name] = rune(0xA0 + i)
|
|
86
|
+
}
|
|
87
|
+
for name, r := range map[string]rune{"amp": '&', "lt": '<', "gt": '>', "quot": '"'} {
|
|
88
|
+
m[name+";"] = r
|
|
89
|
+
m[name] = r
|
|
90
|
+
}
|
|
91
|
+
for name, r := range map[string]rune{
|
|
92
|
+
"apos": '\'', "euro": 0x20AC, "hellip": 0x2026, "mdash": 0x2014,
|
|
93
|
+
"ndash": 0x2013, "lsquo": 0x2018, "rsquo": 0x2019, "sbquo": 0x201A,
|
|
94
|
+
"ldquo": 0x201C, "rdquo": 0x201D, "bdquo": 0x201E, "bull": 0x2022,
|
|
95
|
+
"trade": 0x2122, "larr": 0x2190, "uarr": 0x2191, "rarr": 0x2192,
|
|
96
|
+
"darr": 0x2193, "harr": 0x2194, "spades": 0x2660, "clubs": 0x2663,
|
|
97
|
+
"hearts": 0x2665, "diams": 0x2666,
|
|
98
|
+
} {
|
|
99
|
+
m[name+";"] = r
|
|
100
|
+
}
|
|
101
|
+
return m
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// unescapeEntity reads an entity like "<" at the start of s (s[0] is '&')
|
|
105
|
+
// and returns the text it stands for and how many code units it spans. A
|
|
106
|
+
// reference it does not know stands for itself, one unit long.
|
|
107
|
+
func unescapeEntity(s string) (text string, n int) {
|
|
108
|
+
if len(s) <= 1 {
|
|
109
|
+
return "&", 1
|
|
110
|
+
}
|
|
111
|
+
i := 1
|
|
112
|
+
if s[i] == '#' {
|
|
113
|
+
if len(s) <= 3 { // We need to have at least "&#.".
|
|
114
|
+
return "&", 1
|
|
115
|
+
}
|
|
116
|
+
i++
|
|
117
|
+
c := s[i]
|
|
118
|
+
hex := false
|
|
119
|
+
if c == 'x' || c == 'X' {
|
|
120
|
+
hex = true
|
|
121
|
+
i++
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
var x rune
|
|
125
|
+
for i < len(s) {
|
|
126
|
+
c = s[i]
|
|
127
|
+
i++
|
|
128
|
+
if hex {
|
|
129
|
+
if '0' <= c && c <= '9' {
|
|
130
|
+
x = 16*x + rune(c) - '0'
|
|
131
|
+
continue
|
|
132
|
+
} else if 'a' <= c && c <= 'f' {
|
|
133
|
+
x = 16*x + rune(c) - 'a' + 10
|
|
134
|
+
continue
|
|
135
|
+
} else if 'A' <= c && c <= 'F' {
|
|
136
|
+
x = 16*x + rune(c) - 'A' + 10
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
} else if '0' <= c && c <= '9' {
|
|
140
|
+
x = 10*x + rune(c) - '0'
|
|
141
|
+
continue
|
|
142
|
+
}
|
|
143
|
+
if c != ';' {
|
|
144
|
+
i--
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if i <= 3 { // No characters matched.
|
|
150
|
+
return "&", 1
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if 0x80 <= x && x <= 0x9F {
|
|
154
|
+
// Replace characters from Windows-1252 with UTF-8 equivalents.
|
|
155
|
+
x = replacementTable[x-0x80]
|
|
156
|
+
} else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x < 0 || x > 0x10FFFF {
|
|
157
|
+
// Replace invalid characters with the replacement character.
|
|
158
|
+
x = '\uFFFD'
|
|
159
|
+
}
|
|
160
|
+
return string(x), i
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Consume the maximum number of characters possible, with the
|
|
164
|
+
// consumed characters matching one of the named references.
|
|
165
|
+
for i < len(s) {
|
|
166
|
+
c := s[i]
|
|
167
|
+
i++
|
|
168
|
+
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
|
|
169
|
+
continue
|
|
170
|
+
}
|
|
171
|
+
if c != ';' {
|
|
172
|
+
i--
|
|
173
|
+
}
|
|
174
|
+
break
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
entityName := s[1:i]
|
|
178
|
+
if len(entityName) == 0 {
|
|
179
|
+
return "&", 1
|
|
180
|
+
}
|
|
181
|
+
entity := entities
|
|
182
|
+
if x := entity[entityName]; x != 0 {
|
|
183
|
+
return string(x), i
|
|
184
|
+
}
|
|
185
|
+
maxLen := len(entityName) - 1
|
|
186
|
+
if maxLen > longestEntityWithoutSemicolon {
|
|
187
|
+
maxLen = longestEntityWithoutSemicolon
|
|
188
|
+
}
|
|
189
|
+
for j := maxLen; j > 1; j-- {
|
|
190
|
+
if x := entity[entityName[:j]]; x != 0 {
|
|
191
|
+
return string(x), j + 1
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return s[:i], i
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// EscapeString escapes special characters like "<" to become "<". It
|
|
198
|
+
// escapes only five such characters: <, >, &, ' and ".
|
|
199
|
+
// [UnescapeString](EscapeString(s)) == s always holds, but the converse isn't
|
|
200
|
+
// always true.
|
|
201
|
+
func EscapeString(s string) string {
|
|
202
|
+
out := ""
|
|
203
|
+
last := 0
|
|
204
|
+
for i := 0; i < len(s); i++ {
|
|
205
|
+
var rep string
|
|
206
|
+
switch s[i] {
|
|
207
|
+
case '&':
|
|
208
|
+
rep = "&"
|
|
209
|
+
case '\'':
|
|
210
|
+
rep = "'" // "'" is shorter than "'" and apos was not in HTML until HTML5.
|
|
211
|
+
case '<':
|
|
212
|
+
rep = "<"
|
|
213
|
+
case '>':
|
|
214
|
+
rep = ">"
|
|
215
|
+
case '"':
|
|
216
|
+
rep = """ // """ is shorter than """.
|
|
217
|
+
default:
|
|
218
|
+
continue
|
|
219
|
+
}
|
|
220
|
+
out += s[last:i] + rep
|
|
221
|
+
last = i + 1
|
|
222
|
+
}
|
|
223
|
+
if last == 0 {
|
|
224
|
+
return s
|
|
225
|
+
}
|
|
226
|
+
return out + s[last:]
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// UnescapeString unescapes entities like "<" to become "<". It unescapes a
|
|
230
|
+
// larger range of entities than [EscapeString] escapes. For example, "á"
|
|
231
|
+
// unescapes to "á", as does "á" and "á".
|
|
232
|
+
// UnescapeString([EscapeString](s)) == s always holds, but the converse isn't
|
|
233
|
+
// always true.
|
|
234
|
+
func UnescapeString(s string) string {
|
|
235
|
+
out := ""
|
|
236
|
+
last := 0
|
|
237
|
+
for i := 0; i < len(s); {
|
|
238
|
+
if s[i] != '&' {
|
|
239
|
+
i++
|
|
240
|
+
continue
|
|
241
|
+
}
|
|
242
|
+
text, n := unescapeEntity(s[i:])
|
|
243
|
+
out += s[last:i] + text
|
|
244
|
+
i += n
|
|
245
|
+
last = i
|
|
246
|
+
}
|
|
247
|
+
if last == 0 {
|
|
248
|
+
return s
|
|
249
|
+
}
|
|
250
|
+
return out + s[last:]
|
|
251
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
// Package fmtrt is the contract between package fmt and the code the
|
|
6
|
+
// compiler generates for each package that formats values.
|
|
7
|
+
//
|
|
8
|
+
// Go's fmt learns the type of every operand by reflection. Here the compiler
|
|
9
|
+
// knows it statically: it describes an operand as an Arg (a kind, the value
|
|
10
|
+
// in a field of that kind, and closures that reach the parts of a composite)
|
|
11
|
+
// and fmt only reads the description. An operand that arrives through an
|
|
12
|
+
// interface is described by the lookups packages register with Register.
|
|
13
|
+
package fmtrt
|
|
14
|
+
|
|
15
|
+
// The kinds of an Arg.
|
|
16
|
+
const (
|
|
17
|
+
KNone = iota // not described: format the value in V
|
|
18
|
+
KBool // B
|
|
19
|
+
KInt // I, any signed integer type
|
|
20
|
+
KUint // U, any unsigned integer type
|
|
21
|
+
KFloat // R, any float type
|
|
22
|
+
KComplex // R and Im, any complex type
|
|
23
|
+
KString // S
|
|
24
|
+
KStruct // N fields, Field
|
|
25
|
+
KPtr // Nil, Ptr, Inner
|
|
26
|
+
KSlice // Nil, N elements, Elem
|
|
27
|
+
KArray // N elements, Elem
|
|
28
|
+
KMap // Nil, N entries, Entries
|
|
29
|
+
KFunc // Nil, Ptr
|
|
30
|
+
KInterface // V holds the operand, formatted by its dynamic type
|
|
31
|
+
KChan // Nil, Ptr
|
|
32
|
+
KUnsafePtr // Nil, Ptr
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
// Stringer, GoStringer and Error-only views of a value, kept apart from
|
|
36
|
+
// package fmt so that the generated code needs only this package.
|
|
37
|
+
type Stringer interface {
|
|
38
|
+
String() string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type GoStringer interface {
|
|
42
|
+
GoString() string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Arg describes one operand.
|
|
46
|
+
type Arg struct {
|
|
47
|
+
K int // the kind, one of the K constants
|
|
48
|
+
Size int // the bit size of a number (8, 16, 32, 64 or 0 for int, uint and uintptr)
|
|
49
|
+
T string // the Go type, as %T prints it
|
|
50
|
+
B bool
|
|
51
|
+
I int64
|
|
52
|
+
U uint64
|
|
53
|
+
R float64
|
|
54
|
+
Im float64
|
|
55
|
+
S string
|
|
56
|
+
V any // the operand itself, when K is KNone or KInterface
|
|
57
|
+
|
|
58
|
+
// The methods of the static type that fmt calls. They are set only
|
|
59
|
+
// where Go would call them: the type's method set holds the method and,
|
|
60
|
+
// for a struct field, the field is exported.
|
|
61
|
+
Err error
|
|
62
|
+
Str Stringer
|
|
63
|
+
GoStr GoStringer
|
|
64
|
+
|
|
65
|
+
Nil bool
|
|
66
|
+
N int
|
|
67
|
+
Ptr any
|
|
68
|
+
Boxed bool // Ptr is a pointer to a scalar, boxed anew each time it is put in an Arg
|
|
69
|
+
IsBytes bool // a []byte or [N]byte, whose elements are in Bytes
|
|
70
|
+
Bytes []byte
|
|
71
|
+
Field func(i int) (string, Arg) // the name and value of field i
|
|
72
|
+
Elem func(i int) Arg // element i
|
|
73
|
+
Entries func() []Entry // the entries of a map
|
|
74
|
+
Inner func() Arg // what a non-nil pointer points to
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Entry is one key and value of a map.
|
|
78
|
+
type Entry struct {
|
|
79
|
+
Key Arg
|
|
80
|
+
Val Arg
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
type registry struct {
|
|
84
|
+
keys []string
|
|
85
|
+
lookups []func(v any) (Arg, bool)
|
|
86
|
+
scalars []numbered
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// numbered is a pointer to a scalar that has been given an id; same reports
|
|
90
|
+
// whether a value is that pointer.
|
|
91
|
+
type numbered struct {
|
|
92
|
+
same func(v any) bool
|
|
93
|
+
id uint64
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
var reg = ®istry{}
|
|
97
|
+
|
|
98
|
+
func (r *registry) add(key string, f func(v any) (Arg, bool)) {
|
|
99
|
+
for _, k := range r.keys {
|
|
100
|
+
if k == key {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
r.keys = append(r.keys, key)
|
|
105
|
+
r.lookups = append(r.lookups, f)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Register adds a package's lookup, which describes the values of that
|
|
109
|
+
// package's types held in an interface. A key registers once, so a call may
|
|
110
|
+
// be repeated: it identifies the lookup, and it returns true so that it can
|
|
111
|
+
// initialise a package-level variable.
|
|
112
|
+
func Register(key string, f func(v any) (Arg, bool)) bool {
|
|
113
|
+
reg.add(key, f)
|
|
114
|
+
return true
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Lookup describes a value held in an interface by asking each registered
|
|
118
|
+
// lookup in turn.
|
|
119
|
+
func Lookup(v any) (Arg, bool) {
|
|
120
|
+
for _, f := range reg.lookups {
|
|
121
|
+
if a, ok := f(v); ok {
|
|
122
|
+
return a, true
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return Arg{}, false
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// PtrID returns a number that identifies the pointer, function or other
|
|
129
|
+
// reference v; 0 for nil.
|
|
130
|
+
func PtrID(v any) uint64 {
|
|
131
|
+
if v == nil {
|
|
132
|
+
return 0
|
|
133
|
+
}
|
|
134
|
+
return ptrID(v)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ArgPtrID returns the identity number of the pointer, function or channel
|
|
138
|
+
// that a holds. A pointer to a scalar is boxed anew each time it is put in an
|
|
139
|
+
// Arg and the host would see a different object, so those are matched by
|
|
140
|
+
// equality against the ones already numbered.
|
|
141
|
+
func ArgPtrID(a Arg) uint64 {
|
|
142
|
+
if !a.Boxed {
|
|
143
|
+
return PtrID(a.Ptr)
|
|
144
|
+
}
|
|
145
|
+
p := a.Ptr
|
|
146
|
+
for _, n := range reg.scalars {
|
|
147
|
+
if n.same(p) {
|
|
148
|
+
return n.id
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
id := PtrID(p)
|
|
152
|
+
reg.remember(p, id)
|
|
153
|
+
return id
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
func (r *registry) remember(p any, id uint64) {
|
|
157
|
+
r.scalars = append(r.scalars, numbered{func(v any) bool { return v == p }, id})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ptrID is the host's stable identity number for an object.
|
|
161
|
+
//
|
|
162
|
+
//gofront:intrinsic fmt_ptr_id
|
|
163
|
+
func ptrID(v any) uint64
|