gofront 1.6.1 → 1.8.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 +45 -49
- package/package.json +12 -8
- package/src/backend/js/expressions.js +1627 -148
- package/src/backend/js/fmt-runtime.js +573 -0
- package/src/backend/js/index.js +508 -102
- package/src/backend/js/runtime.js +1997 -106
- package/src/backend/js/statements.js +931 -87
- package/src/backend/js/stdlib/bits.js +87 -14
- package/src/backend/js/stdlib/builder.js +41 -6
- package/src/backend/js/stdlib/bytes.js +253 -7
- package/src/backend/js/stdlib/errors.js +7 -1
- package/src/backend/js/stdlib/fmt.js +349 -10
- package/src/backend/js/stdlib/index.js +19 -2
- package/src/backend/js/stdlib/json.js +1167 -0
- package/src/backend/js/stdlib/maps.js +0 -8
- package/src/backend/js/stdlib/math.js +17 -1
- package/src/backend/js/stdlib/simd.js +34 -0
- package/src/backend/js/stdlib/slices.js +36 -6
- package/src/backend/js/stdlib/strconv.js +10 -5
- package/src/backend/js/stdlib/strings.js +83 -4
- package/src/backend/js/stdlib/testing.js +7 -0
- package/src/backend/js/stdlib/time.js +79 -55
- package/src/backend/js/stdlib/unicode.js +1 -1
- package/src/backend/js/stdlib/utf8.js +1 -1
- package/src/backend/js/templ.js +38 -76
- package/src/backend/js/type-info.js +272 -0
- package/src/backend/shared/fmt-types.js +188 -0
- package/src/backend/wasm/boundary.js +446 -72
- package/src/backend/wasm/emit-builtins.js +320 -13
- package/src/backend/wasm/emit-exprs.js +1404 -199
- package/src/backend/wasm/emit-maps.js +61 -13
- package/src/backend/wasm/emit-stmts.js +1359 -164
- package/src/backend/wasm/emit.js +518 -74
- package/src/backend/wasm/encode.js +128 -13
- package/src/backend/wasm/globals.js +452 -0
- package/src/backend/wasm/index.js +194 -2489
- package/src/backend/wasm/method-expr.js +381 -0
- package/src/backend/wasm/module-emitter.js +2240 -0
- package/src/backend/wasm/monomorph.js +62 -4
- package/src/backend/wasm/optimize.js +4 -2
- package/src/backend/wasm/prescan.js +397 -0
- package/src/backend/wasm/stdlib/bytes.js +1804 -127
- package/src/backend/wasm/stdlib/core.js +1574 -199
- package/src/backend/wasm/stdlib/index.js +3 -5
- package/src/backend/wasm/stdlib/io.js +1567 -150
- package/src/backend/wasm/stdlib/packages.js +2 -0
- package/src/backend/wasm/stdlib/simd.js +499 -0
- package/src/backend/wasm/stdlib/time.js +1041 -12
- package/src/backend/wasm/types.js +221 -15
- package/src/backend/wasm/variadic.js +93 -0
- package/src/backend/wasm/wat.js +84 -20
- package/src/{cli-core.js → cli/cli-core.js} +236 -10
- package/src/{test-runner.js → cli/test-runner.js} +332 -39
- package/src/{vendor.js → cli/vendor.js} +89 -15
- package/src/compiler.js +107 -269
- package/src/dts-parser.js +71 -14
- package/src/index.js +15 -169
- package/src/{lexer.js → lexer/lexer.js} +102 -55
- package/src/{tokens.js → lexer/tokens.js} +1 -0
- package/src/link/sourcemap.js +97 -0
- package/src/link/stdlib.js +515 -0
- package/src/link/wasm.js +294 -0
- package/src/lower/bounds.js +394 -0
- package/src/lower/boxing.js +1 -6
- package/src/lower/captures.js +176 -32
- package/src/lower/embedding.js +2 -1
- package/src/lower/index.js +26 -18
- package/src/lower/json-codecs.js +1398 -0
- package/src/lower/ownership.js +22 -1
- package/src/lower/range.js +86 -1
- package/src/lower/reachability.js +132 -0
- package/src/parser/declarations.js +58 -13
- package/src/parser/expressions.js +29 -7
- package/src/parser/index.js +2 -1
- package/src/parser/statements.js +37 -22
- package/src/parser/struct-tag.js +144 -0
- package/src/{templ-parser.js → parser/templ.js} +138 -15
- package/src/parser/types.js +130 -13
- package/src/resolver.js +22 -1
- package/src/typechecker/assignability.js +215 -11
- package/src/typechecker/const-fold.js +356 -0
- package/src/typechecker/constants.js +256 -0
- package/src/typechecker/expressions.js +960 -99
- package/src/typechecker/index.js +491 -72
- package/src/typechecker/init-order.js +330 -0
- package/src/typechecker/resolve.js +596 -52
- package/src/typechecker/statements.js +157 -17
- package/src/typechecker/stdlib/core.js +333 -55
- package/src/typechecker/stdlib/excluded.js +898 -0
- package/src/typechecker/stdlib/extended.js +359 -26
- package/src/typechecker/{stdlib.js → stdlib/index.js} +6 -4
- package/src/typechecker/stdlib/simd.js +123 -0
- package/src/typechecker/termination.js +1 -1
- package/src/typechecker/types.js +165 -26
- package/stdlib/bytes/iter.go +192 -0
- package/stdlib/bytes/search.go +240 -0
- package/stdlib/bytes/split.go +218 -0
- package/stdlib/cmp/cmp.go +65 -0
- package/stdlib/encoding/json/errors.go +31 -0
- package/stdlib/encoding/json/indent.go +71 -0
- package/stdlib/encoding/json/number.go +12 -0
- package/stdlib/encoding/json/stream.go +173 -0
- package/stdlib/errors/overlay.go +12 -0
- package/stdlib/hash/hash.go +53 -0
- package/stdlib/internal/jsonrt/dec.go +738 -0
- package/stdlib/internal/jsonrt/enc.go +366 -0
- package/stdlib/internal/jsonrt/indent.go +135 -0
- package/stdlib/internal/jsonrt/number.go +27 -0
- package/stdlib/internal/jsonrt/reader.go +73 -0
- package/stdlib/internal/jsonrt/scanner.go +649 -0
- package/stdlib/io/io.go +346 -0
- package/stdlib/iter/iter.go +18 -0
- package/stdlib/maps/iter.go +65 -0
- package/stdlib/math/extra.go +270 -0
- package/stdlib/slices/extra.go +73 -0
- package/stdlib/slices/iter.go +113 -0
- package/stdlib/sort/sort.go +561 -0
- package/stdlib/strconv/quote.go +341 -0
- package/stdlib/strings/extra.go +35 -0
- package/stdlib/strings/iter.go +122 -0
- package/stdlib/sync/extra.go +105 -0
- package/stdlib/unicode/unicode.go +112 -0
- package/stdlib/unicode/utf8/bytes.go +239 -0
- package/src/backend/wasm/const-fold.js +0 -205
- package/src/backend/wasm/emit-stdlib.js +0 -13
- /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
- /package/src/{colors.js → cli/colors.js} +0 -0
- /package/src/{dev-server.js → cli/dev-server.js} +0 -0
- /package/src/{minifier.js → cli/minifier.js} +0 -0
- /package/src/{project-config.js → cli/project-config.js} +0 -0
- /package/src/{pwa.js → cli/pwa.js} +0 -0
- /package/src/{templ-lexer.js → lexer/templ-lexer.js} +0 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
// Copyright 2010 The Go Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
//go:build gofront
|
|
6
|
+
|
|
7
|
+
//gofront:target both
|
|
8
|
+
|
|
9
|
+
package jsonrt
|
|
10
|
+
|
|
11
|
+
import (
|
|
12
|
+
"encoding/base64"
|
|
13
|
+
"errors"
|
|
14
|
+
"math"
|
|
15
|
+
"sort"
|
|
16
|
+
"strconv"
|
|
17
|
+
"unicode/utf8"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
// An UnsupportedValueError is returned by Marshal when attempting to encode
|
|
21
|
+
// an unsupported value.
|
|
22
|
+
type UnsupportedValueError struct {
|
|
23
|
+
Str string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func (e *UnsupportedValueError) Error() string {
|
|
27
|
+
return "json: unsupported value: " + e.Str
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// UnsupportedTypeError is returned by Marshal when attempting to encode an
|
|
31
|
+
// unsupported value type.
|
|
32
|
+
type UnsupportedTypeError struct {
|
|
33
|
+
Type string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func (e *UnsupportedTypeError) Error() string {
|
|
37
|
+
return "json: unsupported type: " + e.Type
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// A MarshalerError represents an error from calling a MarshalJSON method.
|
|
41
|
+
type MarshalerError struct {
|
|
42
|
+
Type string
|
|
43
|
+
Err error
|
|
44
|
+
sourceFunc string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func (e *MarshalerError) Error() string {
|
|
48
|
+
srcFunc := e.sourceFunc
|
|
49
|
+
if srcFunc == "" {
|
|
50
|
+
srcFunc = "MarshalJSON"
|
|
51
|
+
}
|
|
52
|
+
return "json: error calling " + srcFunc + " for type " + e.Type + ": " + e.Err.Error()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func (e *MarshalerError) Unwrap() error { return e.Err }
|
|
56
|
+
|
|
57
|
+
// Enc is the state of one Marshal call: the output so far and the first
|
|
58
|
+
// error. After an error every method does nothing.
|
|
59
|
+
type Enc struct {
|
|
60
|
+
B []byte
|
|
61
|
+
Err error
|
|
62
|
+
EscapeHTML bool
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// NewEnc returns an encoder that escapes <, > and & like json.Marshal.
|
|
66
|
+
func NewEnc() *Enc {
|
|
67
|
+
return &Enc{EscapeHTML: OptEscapeHTML}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Result returns the encoded bytes, or the first error.
|
|
71
|
+
func (e *Enc) Result() ([]byte, error) {
|
|
72
|
+
if e.Err != nil {
|
|
73
|
+
return nil, e.Err
|
|
74
|
+
}
|
|
75
|
+
return e.B, nil
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Fail records the first error.
|
|
79
|
+
func (e *Enc) Fail(err error) {
|
|
80
|
+
if e.Err == nil {
|
|
81
|
+
e.Err = err
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// FailType records an unsupported-type error.
|
|
86
|
+
func (e *Enc) FailType(typ string) {
|
|
87
|
+
e.Fail(&UnsupportedTypeError{typ})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Lit appends s, which is already valid JSON text.
|
|
91
|
+
func (e *Enc) Lit(s string) {
|
|
92
|
+
e.B = appendStr(e.B, s)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Byte appends one byte of JSON punctuation.
|
|
96
|
+
func (e *Enc) Byte(c byte) {
|
|
97
|
+
e.B = append(e.B, c)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Null appends null.
|
|
101
|
+
func (e *Enc) Null() {
|
|
102
|
+
e.B = appendStr(e.B, "null")
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Number appends the literal representation of a Number.
|
|
106
|
+
func (e *Enc) Number(v string) {
|
|
107
|
+
if e.Err != nil {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
if v == "" {
|
|
111
|
+
e.B = append(e.B, '0')
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
if !isValidNumber(v) {
|
|
115
|
+
e.Fail(fmt.Errorf("json: invalid number literal %q", v))
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
e.B = appendStr(e.B, v)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func isValidNumber(s string) bool {
|
|
122
|
+
if len(s) == 0 {
|
|
123
|
+
return false
|
|
124
|
+
}
|
|
125
|
+
first := s[0]
|
|
126
|
+
if first != '-' && (first < '0' || first > '9') {
|
|
127
|
+
return false
|
|
128
|
+
}
|
|
129
|
+
return CheckValid([]byte(s)) == nil
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Bool appends true or false.
|
|
133
|
+
func (e *Enc) Bool(v bool) {
|
|
134
|
+
if v {
|
|
135
|
+
e.B = appendStr(e.B, "true")
|
|
136
|
+
} else {
|
|
137
|
+
e.B = appendStr(e.B, "false")
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Int appends a signed integer.
|
|
142
|
+
func (e *Enc) Int(v int64) {
|
|
143
|
+
e.B = strconv.AppendInt(e.B, v, 10)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Uint appends an unsigned integer.
|
|
147
|
+
func (e *Enc) Uint(v uint64) {
|
|
148
|
+
e.B = strconv.AppendUint(e.B, v, 10)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Float appends a floating-point number in the format encoding/json uses.
|
|
152
|
+
func (e *Enc) Float(f float64, bits int) {
|
|
153
|
+
if e.Err != nil {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
if math.IsInf(f, 0) || math.IsNaN(f) {
|
|
157
|
+
e.Fail(&UnsupportedValueError{strconv.FormatFloat(f, 'g', -1, bits)})
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
if f == 0 && math.Signbit(f) {
|
|
161
|
+
e.B = append(e.B, "-0"...)
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
format := floatFormat(f, bits)
|
|
165
|
+
if bits == 32 {
|
|
166
|
+
f = shortest32(f)
|
|
167
|
+
}
|
|
168
|
+
e.B = strconv.AppendFloat(e.B, f, format, -1, 64)
|
|
169
|
+
if format == 'e' {
|
|
170
|
+
e.B = cleanExponent(e.B)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// floatFormat picks 'e' or 'f' as if by ES6 number to string conversion.
|
|
175
|
+
func floatFormat(f float64, bits int) int {
|
|
176
|
+
abs := math.Abs(f)
|
|
177
|
+
if abs == 0 {
|
|
178
|
+
return 'f'
|
|
179
|
+
}
|
|
180
|
+
if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
|
|
181
|
+
return 'e'
|
|
182
|
+
}
|
|
183
|
+
return 'f'
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// cleanExponent turns a trailing e-09 into e-9.
|
|
187
|
+
func cleanExponent(b []byte) []byte {
|
|
188
|
+
n := len(b)
|
|
189
|
+
if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
|
|
190
|
+
b[n-2] = b[n-1]
|
|
191
|
+
b = b[:n-1]
|
|
192
|
+
}
|
|
193
|
+
return b
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// shortest32 returns the float64 whose shortest decimal form is the shortest
|
|
197
|
+
// one that reads back as the same float32 (strconv's 32-bit formatting).
|
|
198
|
+
func shortest32(f float64) float64 {
|
|
199
|
+
want := float32(f)
|
|
200
|
+
for p := 0; p < 9; p++ {
|
|
201
|
+
s := strconv.FormatFloat(f, 'e', p, 64)
|
|
202
|
+
g, _ := strconv.ParseFloat(s, 32)
|
|
203
|
+
if float32(g) == want {
|
|
204
|
+
h, _ := strconv.ParseFloat(s, 64)
|
|
205
|
+
return h
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return f
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Str appends a quoted, escaped string.
|
|
212
|
+
func (e *Enc) Str(s string) {
|
|
213
|
+
e.B = AppendString(e.B, []byte(s), e.EscapeHTML)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// QStr appends a string for the ,string tag option: the quoted form of the
|
|
217
|
+
// quoted form.
|
|
218
|
+
func (e *Enc) QStr(s string) {
|
|
219
|
+
inner := AppendString(nil, []byte(s), e.EscapeHTML)
|
|
220
|
+
e.B = AppendString(e.B, inner, false)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Key appends the separator for member n of an object (a comma when n > 0)
|
|
224
|
+
// and the member name, a plain name that needs no escaping.
|
|
225
|
+
func (e *Enc) Key(n int, name string) {
|
|
226
|
+
if n > 0 {
|
|
227
|
+
e.B = append(e.B, ',')
|
|
228
|
+
}
|
|
229
|
+
e.B = append(e.B, '"')
|
|
230
|
+
e.B = appendStr(e.B, name)
|
|
231
|
+
e.B = append(e.B, '"', ':')
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// KeyStr is Key for a member name that may need escaping.
|
|
235
|
+
func (e *Enc) KeyStr(n int, name string) {
|
|
236
|
+
if n > 0 {
|
|
237
|
+
e.B = append(e.B, ',')
|
|
238
|
+
}
|
|
239
|
+
e.B = AppendString(e.B, []byte(name), e.EscapeHTML)
|
|
240
|
+
e.B = append(e.B, ':')
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Bytes appends a []byte as a base64 string, or null for a nil slice.
|
|
244
|
+
func (e *Enc) Bytes(v []byte) {
|
|
245
|
+
if v == nil {
|
|
246
|
+
e.Null()
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
e.B = append(e.B, '"')
|
|
250
|
+
e.B = appendStr(e.B, base64.StdEncoding.EncodeToString(v))
|
|
251
|
+
e.B = append(e.B, '"')
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Raw appends a json.RawMessage: validated and compacted, null when empty.
|
|
255
|
+
func (e *Enc) Raw(v []byte) {
|
|
256
|
+
if v == nil {
|
|
257
|
+
e.Null()
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
e.Marshaled(v, nil, "json.RawMessage")
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Marshaled appends the result of a MarshalJSON call: validated and
|
|
264
|
+
// compacted, or the call's error wrapped like Go does.
|
|
265
|
+
func (e *Enc) Marshaled(out []byte, err error, typ string) {
|
|
266
|
+
if e.Err != nil {
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
if err == nil {
|
|
270
|
+
var b []byte
|
|
271
|
+
b, err = AppendCompact(e.B, out, e.EscapeHTML)
|
|
272
|
+
if err == nil {
|
|
273
|
+
e.B = b
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
e.Fail(&MarshalerError{typ, err, "MarshalJSON"})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// SortStrings sorts map keys.
|
|
281
|
+
func SortStrings(a []string) {
|
|
282
|
+
sort.Strings(a)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// IntKey and UintKey format integer map keys.
|
|
286
|
+
func IntKey(v int64) string {
|
|
287
|
+
return strconv.FormatInt(v, 10)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
func UintKey(v uint64) string {
|
|
291
|
+
return strconv.FormatUint(v, 10)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// appendEscaped appends the escape sequence for the ASCII byte b.
|
|
295
|
+
func appendEscaped(dst []byte, b byte) []byte {
|
|
296
|
+
switch b {
|
|
297
|
+
case '\\', '"':
|
|
298
|
+
dst = append(dst, '\\')
|
|
299
|
+
dst = append(dst, b)
|
|
300
|
+
case '\b':
|
|
301
|
+
dst = append(dst, '\\', 'b')
|
|
302
|
+
case '\f':
|
|
303
|
+
dst = append(dst, '\\', 'f')
|
|
304
|
+
case '\n':
|
|
305
|
+
dst = append(dst, '\\', 'n')
|
|
306
|
+
case '\r':
|
|
307
|
+
dst = append(dst, '\\', 'r')
|
|
308
|
+
case '\t':
|
|
309
|
+
dst = append(dst, '\\', 't')
|
|
310
|
+
default:
|
|
311
|
+
// This encodes bytes < 0x20 except for \b, \f, \n, \r and \t.
|
|
312
|
+
// If escapeHTML is set, it also escapes <, >, and &
|
|
313
|
+
// because they can lead to security holes when
|
|
314
|
+
// user-controlled strings are rendered into JSON
|
|
315
|
+
// and served to some browsers.
|
|
316
|
+
dst = append(dst, '\\', 'u', '0', '0', hexDigits[b>>4], hexDigits[b&0xF])
|
|
317
|
+
}
|
|
318
|
+
return dst
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// AppendString appends src as a quoted JSON string.
|
|
322
|
+
func AppendString(dst, src []byte, escapeHTML bool) []byte {
|
|
323
|
+
dst = append(dst, '"')
|
|
324
|
+
start := 0
|
|
325
|
+
for i := 0; i < len(src); {
|
|
326
|
+
if b := src[i]; b < utf8.RuneSelf {
|
|
327
|
+
if b >= 0x20 && b != '"' && b != '\\' && (!escapeHTML || (b != '<' && b != '>' && b != '&')) {
|
|
328
|
+
i++
|
|
329
|
+
continue
|
|
330
|
+
}
|
|
331
|
+
dst = append(dst, src[start:i]...)
|
|
332
|
+
dst = appendEscaped(dst, b)
|
|
333
|
+
i++
|
|
334
|
+
start = i
|
|
335
|
+
continue
|
|
336
|
+
}
|
|
337
|
+
c, size := utf8.DecodeRune(src[i:])
|
|
338
|
+
if c == utf8.RuneError && size == 1 {
|
|
339
|
+
dst = append(dst, src[start:i]...)
|
|
340
|
+
dst = appendStr(dst, `�`)
|
|
341
|
+
i += size
|
|
342
|
+
start = i
|
|
343
|
+
continue
|
|
344
|
+
}
|
|
345
|
+
// U+2028 is LINE SEPARATOR.
|
|
346
|
+
// U+2029 is PARAGRAPH SEPARATOR.
|
|
347
|
+
// They are both technically valid characters in JSON strings,
|
|
348
|
+
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
|
349
|
+
// and can lead to security holes there. It is valid JSON to
|
|
350
|
+
// escape them, so we do so unconditionally.
|
|
351
|
+
// See https://en.wikipedia.org/wiki/JSON#Safety.
|
|
352
|
+
if c == '
' || c == '
' {
|
|
353
|
+
dst = append(dst, src[start:i]...)
|
|
354
|
+
dst = append(dst, '\\', 'u', '2', '0', '2', hexDigits[c&0xF])
|
|
355
|
+
i += size
|
|
356
|
+
start = i
|
|
357
|
+
continue
|
|
358
|
+
}
|
|
359
|
+
i += size
|
|
360
|
+
}
|
|
361
|
+
dst = append(dst, src[start:]...)
|
|
362
|
+
dst = append(dst, '"')
|
|
363
|
+
return dst
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
var errNilTarget = errors.New("json: Unmarshal(nil)")
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// Copyright 2010 The Go Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
//go:build gofront
|
|
6
|
+
|
|
7
|
+
//gofront:target both
|
|
8
|
+
|
|
9
|
+
package jsonrt
|
|
10
|
+
|
|
11
|
+
var hexDigits = []byte("0123456789abcdef")
|
|
12
|
+
|
|
13
|
+
func appendStr(dst []byte, s string) []byte {
|
|
14
|
+
for i := 0; i < len(s); i++ {
|
|
15
|
+
dst = append(dst, s[i])
|
|
16
|
+
}
|
|
17
|
+
return dst
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// compactEscape escapes the byte at src[i] when escape is set and it is <, >
|
|
21
|
+
// or & or begins U+2028/U+2029 (E2 80 A8 and E2 80 A9). It returns the grown
|
|
22
|
+
// dst and the new start of the pending unescaped run.
|
|
23
|
+
func compactEscape(dst, src []byte, i, start int, escape bool) ([]byte, int) {
|
|
24
|
+
c := src[i]
|
|
25
|
+
if !escape {
|
|
26
|
+
return dst, start
|
|
27
|
+
}
|
|
28
|
+
if c == '<' || c == '>' || c == '&' {
|
|
29
|
+
dst = append(dst, src[start:i]...)
|
|
30
|
+
dst = append(dst, '\\', 'u', '0', '0', hexDigits[c>>4], hexDigits[c&0xF])
|
|
31
|
+
return dst, i + 1
|
|
32
|
+
}
|
|
33
|
+
if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
|
|
34
|
+
dst = append(dst, src[start:i]...)
|
|
35
|
+
dst = append(dst, '\\', 'u', '2', '0', '2', hexDigits[src[i+2]&0xF])
|
|
36
|
+
return dst, i + 3
|
|
37
|
+
}
|
|
38
|
+
return dst, start
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// AppendCompact appends to dst the JSON-encoded src with insignificant space
|
|
42
|
+
// characters elided. With escape, <, >, & and U+2028/U+2029 are escaped too.
|
|
43
|
+
func AppendCompact(dst, src []byte, escape bool) ([]byte, error) {
|
|
44
|
+
origLen := len(dst)
|
|
45
|
+
scan := newScanner()
|
|
46
|
+
start := 0
|
|
47
|
+
for i, c := range src {
|
|
48
|
+
dst, start = compactEscape(dst, src, i, start, escape)
|
|
49
|
+
v := scan.step(scan, c)
|
|
50
|
+
if v >= scanSkipSpace {
|
|
51
|
+
if v == scanError {
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
if start < i {
|
|
55
|
+
dst = append(dst, src[start:i]...)
|
|
56
|
+
}
|
|
57
|
+
start = i + 1
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if scan.eof() == scanError {
|
|
61
|
+
return dst[:origLen], scan.err
|
|
62
|
+
}
|
|
63
|
+
if start < len(src) {
|
|
64
|
+
dst = append(dst, src[start:]...)
|
|
65
|
+
}
|
|
66
|
+
return dst, nil
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func appendNewline(dst []byte, prefix, indent string, depth int) []byte {
|
|
70
|
+
dst = append(dst, '\n')
|
|
71
|
+
dst = appendStr(dst, prefix)
|
|
72
|
+
for i := 0; i < depth; i++ {
|
|
73
|
+
dst = appendStr(dst, indent)
|
|
74
|
+
}
|
|
75
|
+
return dst
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// AppendIndent appends to dst an indented form of the JSON-encoded src.
|
|
79
|
+
func AppendIndent(dst, src []byte, prefix, indent string) ([]byte, error) {
|
|
80
|
+
origLen := len(dst)
|
|
81
|
+
scan := newScanner()
|
|
82
|
+
needIndent := false
|
|
83
|
+
depth := 0
|
|
84
|
+
for _, c := range src {
|
|
85
|
+
scan.bytes++
|
|
86
|
+
v := scan.step(scan, c)
|
|
87
|
+
if v == scanSkipSpace {
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
if v == scanError {
|
|
91
|
+
break
|
|
92
|
+
}
|
|
93
|
+
if needIndent && v != scanEndObject && v != scanEndArray {
|
|
94
|
+
needIndent = false
|
|
95
|
+
depth++
|
|
96
|
+
dst = appendNewline(dst, prefix, indent, depth)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Emit semantically uninteresting bytes
|
|
100
|
+
// (in particular, punctuation in strings) unmodified.
|
|
101
|
+
if v == scanContinue {
|
|
102
|
+
dst = append(dst, c)
|
|
103
|
+
continue
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Add spacing around real punctuation.
|
|
107
|
+
switch c {
|
|
108
|
+
case '{', '[':
|
|
109
|
+
// delay indent so that empty object and array are formatted as {} and [].
|
|
110
|
+
needIndent = true
|
|
111
|
+
dst = append(dst, c)
|
|
112
|
+
case ',':
|
|
113
|
+
dst = append(dst, c)
|
|
114
|
+
dst = appendNewline(dst, prefix, indent, depth)
|
|
115
|
+
case ':':
|
|
116
|
+
dst = append(dst, c)
|
|
117
|
+
dst = append(dst, ' ')
|
|
118
|
+
case '}', ']':
|
|
119
|
+
if needIndent {
|
|
120
|
+
// suppress indent in empty object/array
|
|
121
|
+
needIndent = false
|
|
122
|
+
} else {
|
|
123
|
+
depth--
|
|
124
|
+
dst = appendNewline(dst, prefix, indent, depth)
|
|
125
|
+
}
|
|
126
|
+
dst = append(dst, c)
|
|
127
|
+
default:
|
|
128
|
+
dst = append(dst, c)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if scan.eof() == scanError {
|
|
132
|
+
return dst[:origLen], scan.err
|
|
133
|
+
}
|
|
134
|
+
return dst, nil
|
|
135
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
package jsonrt
|
|
6
|
+
|
|
7
|
+
import (
|
|
8
|
+
"strconv"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// A Number represents a JSON number literal.
|
|
12
|
+
type Number string
|
|
13
|
+
|
|
14
|
+
// String returns the literal text of the number.
|
|
15
|
+
func (n Number) String() string { return string(n) }
|
|
16
|
+
|
|
17
|
+
// Float64 returns the number as a float64.
|
|
18
|
+
func (n Number) Float64() (float64, error) {
|
|
19
|
+
v, err := strconv.ParseFloat(string(n), 64)
|
|
20
|
+
return v, err
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Int64 returns the number as an int64.
|
|
24
|
+
func (n Number) Int64() (int64, error) {
|
|
25
|
+
v, err := strconv.ParseInt(string(n), 10, 64)
|
|
26
|
+
return v, err
|
|
27
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//go:build gofront
|
|
2
|
+
|
|
3
|
+
//gofront:target both
|
|
4
|
+
|
|
5
|
+
package jsonrt
|
|
6
|
+
|
|
7
|
+
import "io"
|
|
8
|
+
|
|
9
|
+
const readerBufSize = 4096
|
|
10
|
+
|
|
11
|
+
// Reader is the minimal buffered byte reader behind json.Decoder. It offers
|
|
12
|
+
// only what ScanNext and the Decoder need: single-byte reads with one byte of
|
|
13
|
+
// unread, and access to the bytes still buffered.
|
|
14
|
+
type Reader struct {
|
|
15
|
+
rd io.Reader
|
|
16
|
+
buf []byte
|
|
17
|
+
r int
|
|
18
|
+
w int
|
|
19
|
+
err error
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// NewReader returns a Reader that reads from rd.
|
|
23
|
+
func NewReader(rd io.Reader) *Reader {
|
|
24
|
+
return &Reader{rd: rd, buf: make([]byte, readerBufSize)}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ReadByte returns the next byte, or the error that ended the input.
|
|
28
|
+
func (b *Reader) ReadByte() (byte, error) {
|
|
29
|
+
for b.r == b.w {
|
|
30
|
+
if b.err != nil {
|
|
31
|
+
err := b.err
|
|
32
|
+
b.err = nil
|
|
33
|
+
return 0, err
|
|
34
|
+
}
|
|
35
|
+
b.fill()
|
|
36
|
+
}
|
|
37
|
+
c := b.buf[b.r]
|
|
38
|
+
b.r++
|
|
39
|
+
return c, nil
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// UnreadByte steps back over the byte most recently returned by ReadByte.
|
|
43
|
+
func (b *Reader) UnreadByte() {
|
|
44
|
+
if b.r > 0 {
|
|
45
|
+
b.r--
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Buffered returns the bytes that were read from the source but not consumed.
|
|
50
|
+
// The slice is valid until the next read.
|
|
51
|
+
func (b *Reader) Buffered() []byte {
|
|
52
|
+
return b.buf[b.r:b.w]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func (b *Reader) fill() {
|
|
56
|
+
if b.r > 0 {
|
|
57
|
+
copy(b.buf, b.buf[b.r:b.w])
|
|
58
|
+
b.w -= b.r
|
|
59
|
+
b.r = 0
|
|
60
|
+
}
|
|
61
|
+
for i := 0; i < 100; i++ {
|
|
62
|
+
n, err := b.rd.Read(b.buf[b.w:])
|
|
63
|
+
b.w += n
|
|
64
|
+
if err != nil {
|
|
65
|
+
b.err = err
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
if n > 0 {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
b.err = io.ErrNoProgress
|
|
73
|
+
}
|