json-as 1.3.9 → 1.5.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 (122) hide show
  1. package/CHANGELOG.md +60 -19
  2. package/README.md +120 -21
  3. package/assembly/custom/chars.ts +39 -78
  4. package/assembly/deserialize/index/arbitrary.ts +28 -10
  5. package/assembly/deserialize/index/float.ts +2 -4
  6. package/assembly/deserialize/index/integer.ts +2 -4
  7. package/assembly/deserialize/index/object.ts +6 -1
  8. package/assembly/deserialize/index/string.ts +2 -7
  9. package/assembly/deserialize/index/unsigned.ts +2 -4
  10. package/assembly/deserialize/naive/array/arbitrary.ts +3 -136
  11. package/assembly/deserialize/naive/array/array.ts +30 -1
  12. package/assembly/deserialize/naive/array/integer.ts +2 -7
  13. package/assembly/deserialize/naive/array/map.ts +10 -14
  14. package/assembly/deserialize/naive/array/object.ts +10 -14
  15. package/assembly/deserialize/naive/array/struct.ts +19 -1
  16. package/assembly/deserialize/naive/bool.ts +1 -5
  17. package/assembly/deserialize/naive/date.ts +1 -2
  18. package/assembly/deserialize/naive/float.ts +4 -11
  19. package/assembly/deserialize/naive/integer.ts +2 -4
  20. package/assembly/deserialize/naive/map.ts +42 -205
  21. package/assembly/deserialize/naive/object.ts +291 -174
  22. package/assembly/deserialize/naive/raw.ts +1 -5
  23. package/assembly/deserialize/naive/set.ts +3 -6
  24. package/assembly/deserialize/naive/staticarray.ts +2 -4
  25. package/assembly/deserialize/naive/string.ts +68 -24
  26. package/assembly/deserialize/naive/typedarray.ts +1 -2
  27. package/assembly/deserialize/naive/unsigned.ts +2 -4
  28. package/assembly/deserialize/simd/array/integer.ts +5 -13
  29. package/assembly/deserialize/simd/float.ts +5 -12
  30. package/assembly/deserialize/simd/integer.ts +6 -15
  31. package/assembly/deserialize/simd/string.ts +21 -43
  32. package/assembly/deserialize/swar/array/arbitrary.ts +1 -2
  33. package/assembly/deserialize/swar/array/array.ts +2 -4
  34. package/assembly/deserialize/swar/array/bool.ts +2 -4
  35. package/assembly/deserialize/swar/array/box.ts +1 -2
  36. package/assembly/deserialize/swar/array/float.ts +8 -21
  37. package/assembly/deserialize/swar/array/generic.ts +2 -4
  38. package/assembly/deserialize/swar/array/integer.ts +13 -27
  39. package/assembly/deserialize/swar/array/map.ts +1 -2
  40. package/assembly/deserialize/swar/array/object.ts +2 -4
  41. package/assembly/deserialize/swar/array/raw.ts +1 -2
  42. package/assembly/deserialize/swar/array/shared.ts +9 -21
  43. package/assembly/deserialize/swar/array/string.ts +4 -10
  44. package/assembly/deserialize/swar/array/struct.ts +3 -9
  45. package/assembly/deserialize/swar/array.ts +1 -3
  46. package/assembly/deserialize/swar/float.ts +7 -17
  47. package/assembly/deserialize/swar/integer.ts +6 -15
  48. package/assembly/deserialize/swar/string.ts +40 -54
  49. package/assembly/deserialize/swar/typedarray.ts +4 -4
  50. package/assembly/index.d.ts +259 -21
  51. package/assembly/index.ts +1704 -266
  52. package/assembly/serialize/index/arbitrary.ts +70 -4
  53. package/assembly/serialize/index/jsonarray.ts +51 -0
  54. package/assembly/serialize/index/object.ts +39 -14
  55. package/assembly/serialize/index/string.ts +1 -2
  56. package/assembly/serialize/index/typedarray.ts +1 -2
  57. package/assembly/serialize/index.ts +1 -0
  58. package/assembly/serialize/naive/array.ts +23 -34
  59. package/assembly/serialize/naive/bool.ts +0 -1
  60. package/assembly/serialize/naive/float.ts +16 -25
  61. package/assembly/serialize/naive/integer.ts +1 -5
  62. package/assembly/serialize/naive/raw.ts +1 -2
  63. package/assembly/serialize/naive/set.ts +0 -4
  64. package/assembly/serialize/naive/staticarray.ts +0 -5
  65. package/assembly/serialize/naive/string.ts +11 -7
  66. package/assembly/serialize/naive/typedarray.ts +0 -6
  67. package/assembly/serialize/simd/string.ts +1 -3
  68. package/assembly/serialize/swar/string.ts +2 -4
  69. package/assembly/util/atoi-fast.ts +4 -14
  70. package/assembly/util/atoi.ts +1 -2
  71. package/assembly/util/bytes.ts +1 -2
  72. package/assembly/util/idofd.ts +1 -2
  73. package/assembly/util/isSpace.ts +1 -2
  74. package/assembly/util/itoa-fast.ts +9 -15
  75. package/assembly/util/nextPowerOf2.ts +1 -2
  76. package/assembly/util/parsefloat-fast.ts +4 -7
  77. package/assembly/util/ptrToStr.ts +1 -2
  78. package/assembly/util/scanValueEnd.ts +1 -2
  79. package/assembly/util/scanValueEndSimd.ts +198 -0
  80. package/assembly/util/scanValueEndSwar.ts +184 -0
  81. package/assembly/util/scientific.ts +8 -14
  82. package/assembly/util/simd-int.ts +4 -8
  83. package/assembly/util/snp.ts +2 -7
  84. package/assembly/util/stringScan.ts +2 -4
  85. package/assembly/util/swar-int.ts +8 -16
  86. package/assembly/util/swar.ts +2 -4
  87. package/lib/as-bs.ts +57 -42
  88. package/package.json +27 -10
  89. package/transform/lib/builder.d.ts +0 -1
  90. package/transform/lib/builder.js +0 -1
  91. package/transform/lib/index.d.ts +0 -1
  92. package/transform/lib/index.js +617 -326
  93. package/transform/lib/linkers/alias.d.ts +0 -1
  94. package/transform/lib/linkers/alias.js +0 -1
  95. package/transform/lib/linkers/custom.d.ts +0 -1
  96. package/transform/lib/linkers/custom.js +0 -1
  97. package/transform/lib/linkers/imports.d.ts +0 -1
  98. package/transform/lib/linkers/imports.js +0 -1
  99. package/transform/lib/types.d.ts +4 -2
  100. package/transform/lib/types.js +5 -1
  101. package/transform/lib/util.d.ts +0 -1
  102. package/transform/lib/util.js +0 -1
  103. package/transform/lib/visitor.d.ts +0 -1
  104. package/transform/lib/visitor.js +0 -1
  105. package/assembly/util/dragonbox-cache.ts +0 -445
  106. package/assembly/util/dragonbox.ts +0 -660
  107. package/transform/lib/builder.d.ts.map +0 -1
  108. package/transform/lib/builder.js.map +0 -1
  109. package/transform/lib/index.d.ts.map +0 -1
  110. package/transform/lib/index.js.map +0 -1
  111. package/transform/lib/linkers/alias.d.ts.map +0 -1
  112. package/transform/lib/linkers/alias.js.map +0 -1
  113. package/transform/lib/linkers/custom.d.ts.map +0 -1
  114. package/transform/lib/linkers/custom.js.map +0 -1
  115. package/transform/lib/linkers/imports.d.ts.map +0 -1
  116. package/transform/lib/linkers/imports.js.map +0 -1
  117. package/transform/lib/types.d.ts.map +0 -1
  118. package/transform/lib/types.js.map +0 -1
  119. package/transform/lib/util.d.ts.map +0 -1
  120. package/transform/lib/util.js.map +0 -1
  121. package/transform/lib/visitor.d.ts.map +0 -1
  122. package/transform/lib/visitor.js.map +0 -1
@@ -41,11 +41,7 @@ import { hex4_to_u16_swar } from "../../util/swar";
41
41
  * @param dst buffer to write to
42
42
  * @returns number of bytes written
43
43
  */
44
- // @ts-expect-error: @inline is a valid decorator
45
- @inline function copyStringFromSource(
46
- srcStart: usize,
47
- byteLength: usize,
48
- ): string {
44
+ function copyStringFromSource(srcStart: usize, byteLength: usize): string {
49
45
  if (byteLength == 0) return changetype<string>("");
50
46
  const out = __new(byteLength, idof<string>());
51
47
  memory.copy(out, srcStart, byteLength);
@@ -61,8 +57,7 @@ import { hex4_to_u16_swar } from "../../util/swar";
61
57
  // NOTE: vs the prior overflow scanner this is faster on dense and sparse
62
58
  // escaping but ~20% slower on sustained moderate-density escaping (escape
63
59
  // every ~20 chars), where multi-escape-per-block had an edge.
64
- // @ts-expect-error: @inline is a valid decorator
65
- @inline function deserializeEscapedString_SWAR(
60
+ function deserializeEscapedString_SWAR(
66
61
  payloadStart: usize,
67
62
  escapeStart: usize,
68
63
  srcEnd: usize,
@@ -80,20 +75,20 @@ import { hex4_to_u16_swar } from "../../util/swar";
80
75
 
81
76
  while (srcStart <= srcEnd8) {
82
77
  const block = load<u64>(srcStart);
83
- let mask = inline.always(backslash_mask_unsafe(block));
78
+ let mask = backslash_mask_unsafe(block);
84
79
  if (mask == 0) {
85
80
  store<u64>(bs.offset, block);
86
81
  bs.offset += 8;
87
82
  srcStart += 8;
88
83
  if (
89
84
  srcStart <= srcEnd8 &&
90
- inline.always(backslash_mask_unsafe(load<u64>(srcStart))) == 0
85
+ backslash_mask_unsafe(load<u64>(srcStart)) == 0
91
86
  ) {
92
87
  const runStart = srcStart;
93
88
  srcStart += 8;
94
89
  while (
95
90
  srcStart <= srcEnd8 &&
96
- inline.always(backslash_mask_unsafe(load<u64>(srcStart))) == 0
91
+ backslash_mask_unsafe(load<u64>(srcStart)) == 0
97
92
  ) {
98
93
  srcStart += 8;
99
94
  }
@@ -162,8 +157,8 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
162
157
  const srcEnd16Fast = srcEnd - 16;
163
158
 
164
159
  while (srcStart < srcEnd16Fast) {
165
- const m0 = inline.always(backslash_mask_unsafe(load<u64>(srcStart)));
166
- const m1 = inline.always(backslash_mask_unsafe(load<u64>(srcStart, 8)));
160
+ const m0 = backslash_mask_unsafe(load<u64>(srcStart));
161
+ const m1 = backslash_mask_unsafe(load<u64>(srcStart, 8));
167
162
  if ((m0 | m1) != 0) break;
168
163
  srcStart += 16;
169
164
  }
@@ -183,7 +178,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
183
178
 
184
179
  while (srcStart < srcEnd8) {
185
180
  const block = load<u64>(srcStart);
186
- let mask = inline.always(backslash_mask_unsafe(block));
181
+ let mask = backslash_mask_unsafe(block);
187
182
 
188
183
  if (mask === 0) {
189
184
  srcStart += 8;
@@ -199,9 +194,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
199
194
  // Detect false positive (code unit where low byte is 0x5C)
200
195
  if ((header & 0xffff) !== 0x5c) continue;
201
196
 
202
- return inline.always(
203
- deserializeEscapedString_SWAR(payloadStart, srcIdx, srcEnd),
204
- );
197
+ return deserializeEscapedString_SWAR(payloadStart, srcIdx, srcEnd);
205
198
  } while (mask !== 0);
206
199
 
207
200
  srcStart += 8;
@@ -209,9 +202,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
209
202
 
210
203
  while (srcStart < srcEnd) {
211
204
  if (load<u16>(srcStart) == BACK_SLASH) {
212
- return inline.always(
213
- deserializeEscapedString_SWAR(payloadStart, srcStart, srcEnd),
214
- );
205
+ return deserializeEscapedString_SWAR(payloadStart, srcStart, srcEnd);
215
206
  }
216
207
  srcStart += 2;
217
208
  }
@@ -220,8 +211,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
220
211
  }
221
212
 
222
213
  // Writes into the destination field, reusing or resizing the backing string.
223
- // @ts-expect-error: @inline is a valid decorator
224
- @inline function writeStringToField(
214
+ function writeStringToField(
225
215
  dstFieldPtr: usize,
226
216
  srcStart: usize,
227
217
  byteLength: u32,
@@ -251,15 +241,14 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
251
241
  // the next unread src pointer.
252
242
  //
253
243
  // HYBRID strategy (validated against the prior run-copy scanner across escape
254
- // densities see __benches__/custom/swar-string-deser-hybrid-h2h: +17–70%):
244
+ // densities - see __benches__/custom/swar-string-deser-hybrid-h2h: +17–70%):
255
245
  // * Escape-bearing block: one optimistic whole-block u64 store copies the
256
246
  // plain prefix for free, then the (scalar-confirmed) escape is decoded.
257
247
  // * Clean block: stream the first one, then if the clean run continues switch
258
248
  // to one bulk memory.copy for the remainder.
259
249
  // SWAR masks carry high-byte false positives, so each hit is confirmed
260
250
  // scalarly before acting.
261
- // @ts-expect-error: @inline is a valid decorator
262
- @inline function deserializeEscapedStringField_SWAR(
251
+ function deserializeEscapedStringField_SWAR(
263
252
  payloadStart: usize,
264
253
  escapeStart: usize,
265
254
  srcEnd: usize,
@@ -278,20 +267,20 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
278
267
 
279
268
  while (srcStart <= srcEnd8) {
280
269
  const block = load<u64>(srcStart);
281
- let mask = inline.always(backslash_or_quote_mask(block));
270
+ let mask = backslash_or_quote_mask(block);
282
271
  if (mask == 0) {
283
272
  store<u64>(bs.offset, block);
284
273
  bs.offset += 8;
285
274
  srcStart += 8;
286
275
  if (
287
276
  srcStart <= srcEnd8 &&
288
- inline.always(backslash_or_quote_mask(load<u64>(srcStart))) == 0
277
+ backslash_or_quote_mask(load<u64>(srcStart)) == 0
289
278
  ) {
290
279
  const runStart = srcStart;
291
280
  srcStart += 8;
292
281
  while (
293
282
  srcStart <= srcEnd8 &&
294
- inline.always(backslash_or_quote_mask(load<u64>(srcStart))) == 0
283
+ backslash_or_quote_mask(load<u64>(srcStart)) == 0
295
284
  ) {
296
285
  srcStart += 8;
297
286
  }
@@ -371,8 +360,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
371
360
  return srcStart;
372
361
  }
373
362
 
374
- // @ts-expect-error: @inline is a valid decorator
375
- @inline function deserializeEscapedStringContinuation_SWAR_MergedTuned(
363
+ function deserializeEscapedStringContinuation_SWAR_MergedTuned(
376
364
  lastPtr: usize,
377
365
  srcStart: usize,
378
366
  srcEnd: usize,
@@ -382,7 +370,7 @@ export function deserializeString_SWAR(srcStart: usize, srcEnd: usize): string {
382
370
 
383
371
  while (srcStart <= srcEnd8) {
384
372
  const blockStart = srcStart;
385
- let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
373
+ let mask = backslash_or_quote_mask(load<u64>(srcStart));
386
374
  if (mask === 0) {
387
375
  srcStart += 8;
388
376
  continue;
@@ -491,16 +479,21 @@ export function deserializeStringField_SWAR<T extends string | null>(
491
479
  if (srcEnd >= 16) {
492
480
  const srcEnd16 = srcEnd - 16;
493
481
  while (srcStart <= srcEnd16) {
494
- const m0 = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
495
- const m1 = inline.always(backslash_or_quote_mask(load<u64>(srcStart, 8)));
496
- if ((m0 | m1) != 0) break;
482
+ // Test the first word before loading the second: short values and keys
483
+ // close (or escape) within the first 8 bytes, so this skips the second
484
+ // load on the common case while still skipping 16 bytes when both clean.
485
+ if (backslash_or_quote_mask(load<u64>(srcStart)) != 0) break;
486
+ if (backslash_or_quote_mask(load<u64>(srcStart, 8)) != 0) {
487
+ srcStart += 8;
488
+ break;
489
+ }
497
490
  srcStart += 16;
498
491
  }
499
492
  }
500
493
 
501
494
  const srcEnd8 = srcEnd - 8;
502
495
  while (srcStart <= srcEnd8) {
503
- let mask = inline.always(backslash_or_quote_mask(load<u64>(srcStart)));
496
+ let mask = backslash_or_quote_mask(load<u64>(srcStart));
504
497
  if (mask === 0) {
505
498
  srcStart += 8;
506
499
  continue;
@@ -520,13 +513,11 @@ export function deserializeStringField_SWAR<T extends string | null>(
520
513
  return srcIdx + 2;
521
514
  }
522
515
  if (char != BACK_SLASH) continue;
523
- return inline.always(
524
- deserializeEscapedStringField_SWAR(
525
- payloadStart,
526
- srcIdx,
527
- srcEnd,
528
- dstFieldPtr,
529
- ),
516
+ return deserializeEscapedStringField_SWAR(
517
+ payloadStart,
518
+ srcIdx,
519
+ srcEnd,
520
+ dstFieldPtr,
530
521
  );
531
522
  } while (mask !== 0);
532
523
 
@@ -544,13 +535,11 @@ export function deserializeStringField_SWAR<T extends string | null>(
544
535
  return srcStart + 2;
545
536
  }
546
537
  if (char == BACK_SLASH) {
547
- return inline.always(
548
- deserializeEscapedStringField_SWAR(
549
- payloadStart,
550
- srcStart,
551
- srcEnd,
552
- dstFieldPtr,
553
- ),
538
+ return deserializeEscapedStringField_SWAR(
539
+ payloadStart,
540
+ srcStart,
541
+ srcEnd,
542
+ dstFieldPtr,
554
543
  );
555
544
  }
556
545
  srcStart += 2;
@@ -567,8 +556,7 @@ export function deserializeStringField_SWAR<T extends string | null>(
567
556
  * so callers must confirm the hit scalarly.
568
557
  * Each matching lane sets itself to 0x80.
569
558
  */
570
- // @ts-expect-error: @inline is a valid decorator
571
- @inline function backslash_or_quote_mask(block: u64): u64 {
559
+ function backslash_or_quote_mask(block: u64): u64 {
572
560
  const b = block ^ 0x005c_005c_005c_005c;
573
561
  const q = block ^ 0x0022_0022_0022_0022;
574
562
  return (
@@ -587,8 +575,7 @@ export function deserializeStringField_SWAR<T extends string | null>(
587
575
  *
588
576
  * Each matching lane sets itself to 0x80.
589
577
  */
590
- // @ts-expect-error: @inline is a valid decorator
591
- @inline function backslash_mask(block: u64): u64 {
578
+ function backslash_mask(block: u64): u64 {
592
579
  const b = block ^ 0x005c_005c_005c_005c;
593
580
  const backslash_mask =
594
581
  (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
@@ -609,8 +596,7 @@ export function deserializeStringField_SWAR<T extends string | null>(
609
596
  * WARNING: The low byte of a code unit *may* be a backslash, thus triggering false positives!
610
597
  * This is useful for a hot path where it is possible to detect the false positive scalarly.
611
598
  */
612
- // @ts-expect-error: @inline is a valid decorator
613
- @inline function backslash_mask_unsafe(block: u64): u64 {
599
+ function backslash_mask_unsafe(block: u64): u64 {
614
600
  const b = block ^ 0x005c_005c_005c_005c;
615
601
  const backslash_mask =
616
602
  (b - 0x0001_0001_0001_0001) & ~b & 0x0080_0080_0080_0080;
@@ -6,10 +6,10 @@
6
6
  //
7
7
  // - **No count pass.** TypedArrays have a fixed length at construction,
8
8
  // so the natural approach is to count first then allocate. We tried
9
- // that with a SWAR comma counter it cut the per-element cost but
9
+ // that with a SWAR comma counter - it cut the per-element cost but
10
10
  // kept us ~30% below the top-level `f64[]` path because the count
11
11
  // scan still touched the whole input twice. Instead we allocate
12
- // worst-case (`(srcEnd - srcStart) >> 2 + 1` elements each
12
+ // worst-case (`(srcEnd - srcStart) >> 2 + 1` elements - each
13
13
  // element needs >= "D," = 2 UTF-16 chars = 4 bytes) and `__renew`
14
14
  // the underlying buffer down to the exact byte count after parsing.
15
15
  // The over-allocation peaks at ~2-3× the final size for typical
@@ -46,7 +46,7 @@ import {
46
46
  * Worst-case element count: each element occupies >= 1 digit + 1
47
47
  * delimiter = 2 UTF-16 chars = 4 bytes. So `(srcEnd - srcStart) >> 2`
48
48
  * upper-bounds the count. Allocating to worst-case lets us skip a
49
- * full count pass over the input at the cost of an over-allocated
49
+ * full count pass over the input - at the cost of an over-allocated
50
50
  * underlying buffer that we trim via `__renew` once we know the
51
51
  * actual element count.
52
52
  *
@@ -125,7 +125,7 @@ export function deserializeTypedArray_SWAR<T extends ArrayLike<number>>(
125
125
  // directly: `__renew` the buffer to the actual byte length and
126
126
  // update the view's `byteLength` and `dataStart`. AS's TypedArray
127
127
  // structure has `buffer`, `dataStart` (= buffer), `byteLength`
128
- // (capacity in bytes) in that order same layout as ArrayBufferView.
128
+ // (capacity in bytes) in that order - same layout as ArrayBufferView.
129
129
  const actualCount = i32(<usize>(writePtr - dataStart) / elementSize);
130
130
  if (actualCount != maxElements) {
131
131
  const actualBytes = <usize>actualCount * elementSize;
@@ -1,57 +1,295 @@
1
1
  /**
2
- * Class decorator that enables the class to be recognized as JSON.
2
+ * Options for the {@link json} class decorator: `@json({ ... })`.
3
3
  */
4
- // @ts-ignore: type
5
- declare function json(..._): void;
4
+ declare class JSONConfig {
5
+ /**
6
+ * Class-level lazy (on-demand) parsing mode. A lazy field stores its raw JSON
7
+ * slice at parse time and only parses it into the field's type on first
8
+ * access; untouched fields pass their original bytes straight through on
9
+ * serialize.
10
+ *
11
+ * - `"none"` *(default)* - every field is parsed eagerly, up-front.
12
+ * - `"auto"` - the transform defers fields whose estimated parse cost is high
13
+ * (nested structs, arrays, maps, long strings) and keeps cheap fields
14
+ * (primitives, enums, `Date`) eager. Use `@eager` to force a field back to
15
+ * eager, or `@lazy` to force one on.
16
+ * - `"all"` - every field is deferred. Best for proxy / filter / forward
17
+ * workloads over large payloads; note it generates a getter and a serialize
18
+ * branch per field, so module size grows with very wide schemas.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * @json({ lazy: "auto" })
23
+ * class Repo {
24
+ * name: string = ""; // cheap -> stays eager
25
+ * owner: Owner = new Owner; // costly -> deferred
26
+ * @eager id: i32 = 0; // opt back out
27
+ * }
28
+ * ```
29
+ */
30
+ lazy?: "none" | "auto" | "all";
31
+ }
6
32
 
7
33
  /**
8
- * Class decorator that enables the class to be recognized as JSON.
34
+ * Marks a class as serializable, generating the (de)serialization methods the
35
+ * runtime needs. Required on every type passed to `JSON.parse` / `JSON.stringify`
36
+ * (including nested types).
37
+ *
38
+ * @param config - Optional {@link JSONConfig} (currently `{ lazy }`).
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * @json
43
+ * class Vec3 {
44
+ * x: f64 = 0;
45
+ * y: f64 = 0;
46
+ * z: f64 = 0;
47
+ * }
48
+ *
49
+ * JSON.stringify(new Vec3()); // '{"x":0.0,"y":0.0,"z":0.0}'
50
+ * JSON.parse<Vec3>('{"x":1,"y":2,"z":3}');
51
+ * ```
52
+ */
53
+ declare function json(config?: JSONConfig): Function;
54
+ // @ts-expect-error: type
55
+ declare function json(..._): void;
56
+ /**
57
+ * Alias for {@link json}. `@serializable` and `@json` are interchangeable.
9
58
  */
10
59
  // @ts-ignore: type
11
60
  declare function serializable(..._): void;
12
61
 
13
62
  /**
14
- * Property decorator that provides an alias name for JSON serialization.
63
+ * Field decorator that overrides the JSON key used for a property, decoupling
64
+ * the wire name from the AssemblyScript field name.
65
+ *
66
+ * @param newName - The key to emit and read for this field.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * @json
71
+ * class User {
72
+ * @alias("user_id") userId: i32 = 0; // <-> {"user_id": 0}
73
+ * }
74
+ * ```
15
75
  */
16
76
  declare function alias(newName: string): Function;
17
77
 
18
78
  /**
19
- * Property decorator that allows omits a field, making it be ignored.
79
+ * Field decorator that excludes a property from JSON entirely: it is never
80
+ * serialized and is ignored during parsing.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * @json
85
+ * class Session {
86
+ * token: string = "";
87
+ * @omit secret: string = ""; // never (de)serialized
88
+ * }
89
+ * ```
20
90
  */
21
91
  // @ts-ignore: type
22
92
  declare function omit(..._): void;
23
93
 
24
94
  /**
25
- * Property decorator that allows a field to be omitted when equal to an Expression.
95
+ * Field decorator that omits a property from the output when a predicate holds.
96
+ * The field is still parsed normally; the condition only affects serialization.
97
+ *
98
+ * @param condition - A predicate that receives the **instance** and returns
99
+ * `true` to omit the field - `(self: T) => boolean` - or a string expression
100
+ * evaluated in the instance's scope (reference fields via `this`).
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * @json
105
+ * class Player {
106
+ * age: i32 = 0;
107
+ * @omitif((self: Player) => self.age < 18) email: string = ""; // arrow form
108
+ * @omitif("this.age < 18") phone: string = ""; // string form
109
+ * }
110
+ * ```
26
111
  */
27
- declare function omitif(
28
- condition: string | ((value: any) => boolean),
29
- ): Function;
112
+ declare function omitif(condition: string | ((self: any) => boolean)): Function;
30
113
 
31
114
  /**
32
- * Property decorator that allows a field to be omitted when a property is null.
115
+ * Field decorator that omits a property from the output when its value is
116
+ * `null`. Shorthand for the common nullable case; the field is still parsed.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * @json
121
+ * class Profile {
122
+ * @omitnull bio: string | null = null; // key absent when null
123
+ * }
124
+ * ```
33
125
  */
34
126
  // @ts-ignore: type
35
- declare function omitnull(..._): Function;
127
+ declare function omitnull(..._): void;
36
128
 
37
129
  /**
38
- * Method decorator that denotes a function to handle that schema's serialization.
130
+ * Field decorator that marks a property as optional for deserialization: the
131
+ * key may be absent from (or appear anywhere in) the input, and the field keeps
132
+ * its default. Unlike `@omitnull`/`@omitif` it does NOT omit the field on
133
+ * serialize and has no nullability requirement - it only opts the field into
134
+ * the order-tolerant fast path.
135
+ *
136
+ * @example
137
+ * ```ts
138
+ * @json
139
+ * class Tweet {
140
+ * @optional retweeted_status: Retweet | null = null; // key may be absent
141
+ * }
142
+ * ```
39
143
  */
40
144
  // @ts-ignore: type
41
- declare function serializer(..._): any;
145
+ declare function optional(..._): void;
42
146
 
43
147
  /**
44
- * Method decorator that denotes a function to handle that schema's deserialization.
148
+ * Field decorator that defers parsing of a property until it is first read
149
+ * (on-demand / lazy parsing). The raw JSON slice is stored at parse time and
150
+ * materialized into the field's type on first access, then cached; an untouched
151
+ * field round-trips by copying its original bytes - never re-parsed or
152
+ * re-serialized.
153
+ *
154
+ * Equivalent to the `JSON.Lazy<T>` type-wrapper form. Pays off for fields you
155
+ * usually skip or forward; reading a deferred field is a one-time cost.
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * @json
160
+ * class Repo {
161
+ * name: string = ""; // eager
162
+ * @lazy owner: Owner = new Owner; // parsed only when `repo.owner` is read
163
+ * }
164
+ * ```
45
165
  */
46
166
  // @ts-ignore: type
47
- declare function deserializer(..._): any;
167
+ declare function lazy(..._): void;
48
168
 
49
- declare enum JSONMode {
50
- SWAR = 0,
51
- SIMD = 1,
52
- NAIVE = 2,
53
- }
169
+ /**
170
+ * Field decorator that forces a property to be parsed eagerly, opting it out of
171
+ * class-level lazy deferral (`@json({ lazy: "auto" | "all" })`). No effect on a
172
+ * class that is not lazy.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * @json({ lazy: "all" })
177
+ * class Event {
178
+ * @eager id: i32 = 0; // always parsed up-front
179
+ * payload: Payload = new Payload; // deferred
180
+ * }
181
+ * ```
182
+ */
183
+ // @ts-ignore: type
184
+ declare function eager(..._): void;
185
+
186
+ /**
187
+ * Method decorator marking a member as the class's custom serializer, replacing
188
+ * the generated serialization. The method receives the instance and must return
189
+ * a **valid JSON string**. Pair with {@link deserializer}.
190
+ *
191
+ * @param shape - Optional JSON value shape the output conforms to - one of
192
+ * `"any"` (default), `"string"`, `"number"`, `"object"`, `"array"`,
193
+ * `"boolean"`, or `"null"`.
194
+ *
195
+ * @example
196
+ * ```ts
197
+ * @json
198
+ * class Point {
199
+ * x: f64 = 0;
200
+ * y: f64 = 0;
201
+ * constructor(x: f64, y: f64) {
202
+ * this.x = x;
203
+ * this.y = y;
204
+ * }
205
+ *
206
+ * // Serialize a Point to a single JSON string.
207
+ * @serializer("string")
208
+ * serializer(self: Point): string {
209
+ * return JSON.stringify(`${self.x},${self.y}`);
210
+ * }
211
+ *
212
+ * // ...and back. Always return a fresh instance.
213
+ * @deserializer("string")
214
+ * deserializer(data: string): Point {
215
+ * const raw = JSON.parse<string>(data);
216
+ * const c = raw.indexOf(",");
217
+ * return new Point(f64.parse(raw.slice(0, c)), f64.parse(raw.slice(c + 1)));
218
+ * }
219
+ * }
220
+ *
221
+ * JSON.stringify(new Point(3.5, -9.2)); // '"3.5,-9.2"'
222
+ * JSON.parse<Point>('"3.5,-9.2"'); // Point { x: 3.5, y: -9.2 }
223
+ * ```
224
+ */
225
+ // @ts-ignore: type
226
+ declare function serializer(
227
+ shape?: "any" | "string" | "number" | "object" | "array" | "boolean" | "null",
228
+ ): any;
54
229
 
230
+ /**
231
+ * Method decorator marking a member as the class's custom deserializer,
232
+ * replacing the generated deserialization. The method receives the raw JSON
233
+ * string and must return a **new** instance - never assume an existing
234
+ * destination is reused. Pair with {@link serializer} (see it for a full,
235
+ * round-tripping example).
236
+ *
237
+ * @param shape - Optional JSON value shape the input conforms to - one of
238
+ * `"any"` (default), `"string"`, `"number"`, `"object"`, `"array"`,
239
+ * `"boolean"`, or `"null"`.
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * @deserializer("string")
244
+ * deserializer(data: string): Point {
245
+ * const raw = JSON.parse<string>(data); // unwrap the JSON string
246
+ * const c = raw.indexOf(",");
247
+ * return new Point(f64.parse(raw.slice(0, c)), f64.parse(raw.slice(c + 1)));
248
+ * }
249
+ * ```
250
+ */
251
+ // @ts-ignore: type
252
+ declare function deserializer(
253
+ shape?: "any" | "string" | "number" | "object" | "array" | "boolean" | "null",
254
+ ): any;
255
+
256
+ /**
257
+ * The active {@link JSONMode}, injected by the transform from the `JSON_MODE`
258
+ * build-time environment variable (default `SWAR`). Set it on the `asc`
259
+ * command/build env; `SIMD` additionally requires `--enable simd`.
260
+ *
261
+ * @example
262
+ * ```sh
263
+ * JSON_MODE=SIMD asc app.ts --transform json-as/transform --enable simd
264
+ * JSON_MODE=SWAR asc app.ts --transform json-as/transform # default
265
+ * JSON_MODE=NAIVE asc app.ts --transform json-as/transform
266
+ * ```
267
+ */
55
268
  declare const JSON_MODE: JSONMode;
269
+
270
+ /**
271
+ * Whether the string cache is enabled (default off). Injected from the
272
+ * `JSON_CACHE` build-time environment variable. When on, repeated strings are
273
+ * reused to speed up string-heavy serialization.
274
+ *
275
+ * @example
276
+ * ```sh
277
+ * JSON_CACHE=true asc app.ts --transform json-as/transform # default size
278
+ * JSON_CACHE=512kb asc app.ts --transform json-as/transform # enable + size
279
+ * JSON_CACHE=false asc app.ts --transform json-as/transform # off (default)
280
+ * ```
281
+ */
56
282
  declare const JSON_CACHE: bool;
283
+
284
+ /**
285
+ * The string-cache size in bytes when {@link JSON_CACHE} is enabled. Both this
286
+ * and {@link JSON_CACHE} are derived from the single `JSON_CACHE` build-time
287
+ * environment variable, which accepts raw bytes (`JSON_CACHE=1048576`), bit
288
+ * units (`512kb`, `2mb`, `1gb`), or byte units (`64KB`, `2MB`, `1GB`).
289
+ *
290
+ * @example
291
+ * ```sh
292
+ * JSON_CACHE=1mb asc app.ts --transform json-as/transform # JSON_CACHE_SIZE == 1048576
293
+ * ```
294
+ */
57
295
  declare const JSON_CACHE_SIZE: usize;