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.
Files changed (132) hide show
  1. package/README.md +45 -49
  2. package/package.json +12 -8
  3. package/src/backend/js/expressions.js +1627 -148
  4. package/src/backend/js/fmt-runtime.js +573 -0
  5. package/src/backend/js/index.js +508 -102
  6. package/src/backend/js/runtime.js +1997 -106
  7. package/src/backend/js/statements.js +931 -87
  8. package/src/backend/js/stdlib/bits.js +87 -14
  9. package/src/backend/js/stdlib/builder.js +41 -6
  10. package/src/backend/js/stdlib/bytes.js +253 -7
  11. package/src/backend/js/stdlib/errors.js +7 -1
  12. package/src/backend/js/stdlib/fmt.js +349 -10
  13. package/src/backend/js/stdlib/index.js +19 -2
  14. package/src/backend/js/stdlib/json.js +1167 -0
  15. package/src/backend/js/stdlib/maps.js +0 -8
  16. package/src/backend/js/stdlib/math.js +17 -1
  17. package/src/backend/js/stdlib/simd.js +34 -0
  18. package/src/backend/js/stdlib/slices.js +36 -6
  19. package/src/backend/js/stdlib/strconv.js +10 -5
  20. package/src/backend/js/stdlib/strings.js +83 -4
  21. package/src/backend/js/stdlib/testing.js +7 -0
  22. package/src/backend/js/stdlib/time.js +79 -55
  23. package/src/backend/js/stdlib/unicode.js +1 -1
  24. package/src/backend/js/stdlib/utf8.js +1 -1
  25. package/src/backend/js/templ.js +38 -76
  26. package/src/backend/js/type-info.js +272 -0
  27. package/src/backend/shared/fmt-types.js +188 -0
  28. package/src/backend/wasm/boundary.js +446 -72
  29. package/src/backend/wasm/emit-builtins.js +320 -13
  30. package/src/backend/wasm/emit-exprs.js +1404 -199
  31. package/src/backend/wasm/emit-maps.js +61 -13
  32. package/src/backend/wasm/emit-stmts.js +1359 -164
  33. package/src/backend/wasm/emit.js +518 -74
  34. package/src/backend/wasm/encode.js +128 -13
  35. package/src/backend/wasm/globals.js +452 -0
  36. package/src/backend/wasm/index.js +194 -2489
  37. package/src/backend/wasm/method-expr.js +381 -0
  38. package/src/backend/wasm/module-emitter.js +2240 -0
  39. package/src/backend/wasm/monomorph.js +62 -4
  40. package/src/backend/wasm/optimize.js +4 -2
  41. package/src/backend/wasm/prescan.js +397 -0
  42. package/src/backend/wasm/stdlib/bytes.js +1804 -127
  43. package/src/backend/wasm/stdlib/core.js +1574 -199
  44. package/src/backend/wasm/stdlib/index.js +3 -5
  45. package/src/backend/wasm/stdlib/io.js +1567 -150
  46. package/src/backend/wasm/stdlib/packages.js +2 -0
  47. package/src/backend/wasm/stdlib/simd.js +499 -0
  48. package/src/backend/wasm/stdlib/time.js +1041 -12
  49. package/src/backend/wasm/types.js +221 -15
  50. package/src/backend/wasm/variadic.js +93 -0
  51. package/src/backend/wasm/wat.js +84 -20
  52. package/src/{cli-core.js → cli/cli-core.js} +236 -10
  53. package/src/{test-runner.js → cli/test-runner.js} +332 -39
  54. package/src/{vendor.js → cli/vendor.js} +89 -15
  55. package/src/compiler.js +107 -269
  56. package/src/dts-parser.js +71 -14
  57. package/src/index.js +15 -169
  58. package/src/{lexer.js → lexer/lexer.js} +102 -55
  59. package/src/{tokens.js → lexer/tokens.js} +1 -0
  60. package/src/link/sourcemap.js +97 -0
  61. package/src/link/stdlib.js +515 -0
  62. package/src/link/wasm.js +294 -0
  63. package/src/lower/bounds.js +394 -0
  64. package/src/lower/boxing.js +1 -6
  65. package/src/lower/captures.js +176 -32
  66. package/src/lower/embedding.js +2 -1
  67. package/src/lower/index.js +26 -18
  68. package/src/lower/json-codecs.js +1398 -0
  69. package/src/lower/ownership.js +22 -1
  70. package/src/lower/range.js +86 -1
  71. package/src/lower/reachability.js +132 -0
  72. package/src/parser/declarations.js +58 -13
  73. package/src/parser/expressions.js +29 -7
  74. package/src/parser/index.js +2 -1
  75. package/src/parser/statements.js +37 -22
  76. package/src/parser/struct-tag.js +144 -0
  77. package/src/{templ-parser.js → parser/templ.js} +138 -15
  78. package/src/parser/types.js +130 -13
  79. package/src/resolver.js +22 -1
  80. package/src/typechecker/assignability.js +215 -11
  81. package/src/typechecker/const-fold.js +356 -0
  82. package/src/typechecker/constants.js +256 -0
  83. package/src/typechecker/expressions.js +960 -99
  84. package/src/typechecker/index.js +491 -72
  85. package/src/typechecker/init-order.js +330 -0
  86. package/src/typechecker/resolve.js +596 -52
  87. package/src/typechecker/statements.js +157 -17
  88. package/src/typechecker/stdlib/core.js +333 -55
  89. package/src/typechecker/stdlib/excluded.js +898 -0
  90. package/src/typechecker/stdlib/extended.js +359 -26
  91. package/src/typechecker/{stdlib.js → stdlib/index.js} +6 -4
  92. package/src/typechecker/stdlib/simd.js +123 -0
  93. package/src/typechecker/termination.js +1 -1
  94. package/src/typechecker/types.js +165 -26
  95. package/stdlib/bytes/iter.go +192 -0
  96. package/stdlib/bytes/search.go +240 -0
  97. package/stdlib/bytes/split.go +218 -0
  98. package/stdlib/cmp/cmp.go +65 -0
  99. package/stdlib/encoding/json/errors.go +31 -0
  100. package/stdlib/encoding/json/indent.go +71 -0
  101. package/stdlib/encoding/json/number.go +12 -0
  102. package/stdlib/encoding/json/stream.go +173 -0
  103. package/stdlib/errors/overlay.go +12 -0
  104. package/stdlib/hash/hash.go +53 -0
  105. package/stdlib/internal/jsonrt/dec.go +738 -0
  106. package/stdlib/internal/jsonrt/enc.go +366 -0
  107. package/stdlib/internal/jsonrt/indent.go +135 -0
  108. package/stdlib/internal/jsonrt/number.go +27 -0
  109. package/stdlib/internal/jsonrt/reader.go +73 -0
  110. package/stdlib/internal/jsonrt/scanner.go +649 -0
  111. package/stdlib/io/io.go +346 -0
  112. package/stdlib/iter/iter.go +18 -0
  113. package/stdlib/maps/iter.go +65 -0
  114. package/stdlib/math/extra.go +270 -0
  115. package/stdlib/slices/extra.go +73 -0
  116. package/stdlib/slices/iter.go +113 -0
  117. package/stdlib/sort/sort.go +561 -0
  118. package/stdlib/strconv/quote.go +341 -0
  119. package/stdlib/strings/extra.go +35 -0
  120. package/stdlib/strings/iter.go +122 -0
  121. package/stdlib/sync/extra.go +105 -0
  122. package/stdlib/unicode/unicode.go +112 -0
  123. package/stdlib/unicode/utf8/bytes.go +239 -0
  124. package/src/backend/wasm/const-fold.js +0 -205
  125. package/src/backend/wasm/emit-stdlib.js +0 -13
  126. /package/src/{asset-manager.js → cli/asset-manager.js} +0 -0
  127. /package/src/{colors.js → cli/colors.js} +0 -0
  128. /package/src/{dev-server.js → cli/dev-server.js} +0 -0
  129. /package/src/{minifier.js → cli/minifier.js} +0 -0
  130. /package/src/{project-config.js → cli/project-config.js} +0 -0
  131. /package/src/{pwa.js → cli/pwa.js} +0 -0
  132. /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
+ }