json-as 1.1.7 → 1.1.9

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/assembly/index.ts CHANGED
@@ -515,6 +515,12 @@ export namespace JSON {
515
515
  }
516
516
  }
517
517
 
518
+ /**
519
+ * Serializes JSON data but writes directly to the buffer.
520
+ * Should only be used if you know what you are doing.
521
+ * @param src - T
522
+ * @returns void
523
+ */
518
524
  export function __serialize<T>(src: T): void {
519
525
  if (isBoolean<T>()) {
520
526
  serializeBool(src as bool);
@@ -565,6 +571,14 @@ export namespace JSON {
565
571
  }
566
572
  }
567
573
 
574
+ /**
575
+ * Deserializes JSON data directly from the buffer.
576
+ * Should only be used if you know what you are doing.
577
+ * @param srcStart - usize
578
+ * @param srcEnd - usize
579
+ * @param dst - usize
580
+ * @returns void
581
+ */
568
582
  export function __deserialize<T>(srcStart: usize, srcEnd: usize, dst: usize = 0): T {
569
583
  if (isBoolean<T>()) {
570
584
  // @ts-ignore: type
@@ -625,6 +639,127 @@ export namespace JSON {
625
639
  return changetype<string>(out);
626
640
  }
627
641
  }
642
+ /**
643
+ * Methods for use when using JSON methods inside another JSON method or custom serializer/deserializer.
644
+ */
645
+ export namespace internal {
646
+ /**
647
+ * Serializes JSON data. Don't use this directly, use `JSON.stringify` instead.
648
+ * @param data - T
649
+ * @param out - string | null
650
+ * @returns - string
651
+ */
652
+ // @ts-ignore: inline
653
+ @inline export function stringify<T>(data: T, out: string | null = null): string {
654
+ if (isBoolean<T>()) {
655
+ if (out) {
656
+ if (<bool>data == true) {
657
+ out = changetype<string>(__renew(changetype<usize>(out), 8));
658
+ store<u64>(changetype<usize>(out), 28429475166421108);
659
+ } else {
660
+ out = changetype<string>(__renew(changetype<usize>(out), 10));
661
+ store<u64>(changetype<usize>(out), 32370086184550502);
662
+ store<u16>(changetype<usize>(out), 101, 8);
663
+ }
664
+ return out;
665
+ }
666
+ return data ? "true" : "false";
667
+ } else if (isInteger<T>() && !isSigned<T>() && nameof<T>() == "usize" && data == 0) {
668
+ if (out) {
669
+ out = changetype<string>(__renew(changetype<usize>(out), 8));
670
+ store<u64>(changetype<usize>(out), 30399761348886638);
671
+ return out;
672
+ }
673
+ return NULL_WORD;
674
+ } else if (isInteger<T>(data)) {
675
+ if (out) {
676
+ out = changetype<string>(__renew(changetype<usize>(out), sizeof<T>() << 3));
677
+
678
+ // @ts-ignore
679
+ const bytes = itoa_buffered(changetype<usize>(out), data) << 1;
680
+ return (out = changetype<string>(__renew(changetype<usize>(out), bytes)));
681
+ }
682
+ return data.toString();
683
+ } else if (isFloat<T>(data)) {
684
+ if (out) {
685
+ out = changetype<string>(__renew(changetype<usize>(out), 64));
686
+
687
+ // @ts-ignore
688
+ const bytes = dtoa_buffered(changetype<usize>(out), data) << 1;
689
+ return (out = changetype<string>(__renew(changetype<usize>(out), bytes)));
690
+ }
691
+ return data.toString();
692
+ // @ts-ignore: Function is generated by transform
693
+ } else if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
694
+ if (out) {
695
+ out = changetype<string>(__renew(changetype<usize>(out), 8));
696
+ store<u64>(changetype<usize>(out), 30399761348886638);
697
+ return out;
698
+ }
699
+ return NULL_WORD;
700
+ // @ts-ignore
701
+ } else if (isString<nonnull<T>>()) {
702
+ // if (out) {
703
+ // out = changetype<string>(__renew(changetype<usize>(out), bytes(data) + 4));
704
+ // // const oldSize = bs.byteLength;
705
+ // const oldBuf = bs.buffer;
706
+ // const newSize = bytes(data) + 4;
707
+ // const newBuf = __new(newSize, idof<string>());
708
+ // bs.setBuffer(newBuf);
709
+ // serializeString(changetype<string>(data));
710
+ // bs.setBuffer(oldBuf);
711
+ // return changetype<string>(newBuf);
712
+ // }
713
+ // if (ASC_FEATURE_SIMD) {
714
+ // serializeString_SIMD(data as string);
715
+ // } else {
716
+ bs.saveState();
717
+ serializeString(data as string);
718
+ // }
719
+ return bs.cpyOut<string>();
720
+ // @ts-ignore: Supplied by transform
721
+ } else if (isDefined(data.__SERIALIZE)) {
722
+ bs.saveState();
723
+ // @ts-ignore
724
+ inline.always(data.__SERIALIZE(changetype<usize>(data)));
725
+ return bs.cpyOut<string>();
726
+ // @ts-ignore: Supplied by transform
727
+ } else if (data instanceof Date) {
728
+ out = out ? changetype<string>(__renew(changetype<usize>(out), 52)) : changetype<string>(__new(52, idof<string>()));
729
+
730
+ store<u16>(changetype<usize>(out), QUOTE);
731
+ memory.copy(changetype<usize>(out) + 2, changetype<usize>(data.toISOString()), 48);
732
+ store<u16>(changetype<usize>(out), QUOTE, 50);
733
+ return changetype<string>(out);
734
+ } else if (data instanceof Array) {
735
+ bs.saveState();
736
+ // @ts-ignore
737
+ inline.always(serializeArray(changetype<nonnull<T>>(data)));
738
+ return bs.cpyOut<string>();
739
+ } else if (data instanceof Map) {
740
+ bs.saveState();
741
+ // @ts-ignore
742
+ inline.always(serializeMap(changetype<nonnull<T>>(data)));
743
+ return bs.cpyOut<string>();
744
+ } else if (data instanceof JSON.Raw) {
745
+ bs.saveState();
746
+ serializeRaw(data);
747
+ return bs.cpyOut<string>();
748
+ } else if (data instanceof JSON.Value) {
749
+ bs.saveState();
750
+ inline.always(serializeArbitrary(data));
751
+ return bs.cpyOut<string>();
752
+ } else if (data instanceof JSON.Obj) {
753
+ bs.saveState();
754
+ inline.always(serializeObject(data));
755
+ return bs.cpyOut<string>();
756
+ } else if (data instanceof JSON.Box) {
757
+ return JSON.internal.stringify(data.value);
758
+ } else {
759
+ throw new Error(`Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`);
760
+ }
761
+ }
762
+ }
628
763
  }
629
764
 
630
765
  // @ts-ignore: decorator
package/assembly/test.ts CHANGED
@@ -1,218 +1,57 @@
1
1
  import { JSON } from ".";
2
- import { bytes } from "./util";
3
-
4
- @json
5
- class Obj {
6
- public a: string = "hello";
7
- public b: string = "world";
8
- public c: string = '"\t\f\u0000\u0001';
9
- }
10
-
11
- @json
12
- class Vec3 {
13
- x: f32 = 0.0;
14
- y: f32 = 0.0;
15
- z: f32 = 0.0;
16
- }
17
-
18
- @json
19
- class Player {
20
- @alias("first name")
21
- firstName!: string;
22
- lastName!: string;
23
- lastActive!: i32[];
24
- // Drop in a code block, function, or expression that evaluates to a boolean
25
- @omitif((self: Player) => self.age < 18)
26
- age!: i32;
27
-
28
- @omitnull()
29
- pos!: Vec3 | null;
30
- isVerified!: boolean;
31
- }
32
-
33
- @json
34
- class Point {}
35
-
36
- @json
37
- class NewPoint {
38
- x: f64 = 0.0;
39
- y: f64 = 0.0;
40
- constructor(x: f64, y: f64) {
41
- this.x = x;
42
- this.y = y;
43
- }
44
-
45
- @serializer
46
- serializer(self: NewPoint): string {
47
- return `x=${self.x},y=${self.y}`;
48
- }
49
-
50
- @deserializer
51
- deserializer(data: string): NewPoint {
52
- const dataSize = bytes(data);
53
-
54
- const c = data.indexOf(",");
55
- const x = data.slice(2, c);
56
- const y = data.slice(c + 3);
57
-
58
- return new NewPoint(f64.parse(x), f64.parse(y));
59
- }
60
- }
61
-
62
- @json
63
- class InnerObj<T> {
64
- obj: T = instantiate<T>();
65
- }
66
-
67
- @json
68
- class ObjWithBracketString {
69
- data: string = "";
70
- }
71
-
72
- const player: Player = {
73
- firstName: "Jairus",
74
- lastName: "Tanaka",
75
- lastActive: [2, 7, 2025],
76
- age: 18,
77
- pos: {
78
- x: 3.4,
79
- y: 1.2,
80
- z: 8.3,
2
+ import { expect, it } from "./__tests__/lib";
3
+
4
+ it("should parse", () => {
5
+ const str = `{
6
+ "id": "chatcmpl-BbvlnP0ESWa8OForeEjt7AkoIuh3Q",
7
+ "object": "chat.completion",
8
+ "created": 1748379903,
9
+ "model": "gpt-4o-mini-2024-07-18",
10
+ "choices": [
11
+ {
12
+ "index": 0,
13
+ "message": {
14
+ "role": "assistant",
15
+ "content": "Hello! How can I assist you today?",
16
+ "refusal": null,
17
+ "annotations": []
18
+ },
19
+ "logprobs": null,
20
+ "finish_reason": "stop"
21
+ }
22
+ ],
23
+ "usage": {
24
+ "prompt_tokens": 15,
25
+ "completion_tokens": 9,
26
+ "total_tokens": 24,
27
+ "prompt_tokens_details": {
28
+ "cached_tokens": 0,
29
+ "audio_tokens": 0
30
+ },
31
+ "completion_tokens_details": {
32
+ "reasoning_tokens": 0,
33
+ "audio_tokens": 0,
34
+ "accepted_prediction_tokens": 0,
35
+ "rejected_prediction_tokens": 0
36
+ }
81
37
  },
82
- isVerified: true,
83
- };
84
-
85
- const a1 = JSON.stringify("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f");
86
- // console.log("Bytes " + bytes(a1).toString());
87
- console.log("a1: " + a1);
88
-
89
- const obj = new Obj();
90
- const a2 = JSON.stringify(obj);
91
- // console.log("Bytes " + bytes(a2).toString());
92
- console.log("a2: " + a2);
93
-
94
- const a3 = JSON.stringify(player);
95
- // console.log("Bytes " + bytes(a3).toString());
96
- console.log("a3: " + a3);
97
-
98
- const a4 = new JSON.Obj();
99
-
100
- a4.set("x", 1.5);
101
- a4.set("y", 5.4);
102
- a4.set("z", 9.8);
103
- a4.set("obj", obj);
104
- a4.set<boolean>("bool", false);
105
-
106
- console.log("a4: " + JSON.stringify(a4));
107
-
108
- const a5 = JSON.parse<JSON.Obj>('{"foo":"bar"}');
38
+ "service_tier": "default",
39
+ "system_fingerprint": "fp_34a54ae93c"
40
+ }`;
109
41
 
110
- console.log("a5: " + JSON.stringify(a5));
42
+ const output = JSON.parse<OpenAIChatOutput>(str);
111
43
 
112
- const a6 = JSON.parse<JSON.Obj>('{"x":1.5,"y":5.4,"z":9.8,"obj":{"foo":"bar"}}');
44
+ expect(output.id).toBe("chatcmpl-BbvlnP0ESWa8OForeEjt7AkoIuh3Q");
45
+ expect(output.object).toBe("chat.completion");
46
+ expect(output.model).toBe("gpt-4o-mini-2024-07-18");
47
+ expect(output.system_fingerprint).toBe("fp_34a54ae93c"); // fails ("")
48
+ });
113
49
 
114
- console.log("a6: " + JSON.stringify(a6));
115
-
116
- const a7 = JSON.parse<JSON.Value[]>('["string",true,3.14,{"x":1.0,"y":2.0,"z":3.0},[1,2,3,true]]');
117
-
118
- console.log("a7: " + JSON.stringify(a7));
119
-
120
- const a8 = JSON.stringify(["hello", JSON.stringify("world"), "working?"]);
121
-
122
- console.log("a8: " + a8);
123
-
124
- const a9 = JSON.stringify<JSON.Raw>(JSON.Raw.from('"hello world"'));
125
-
126
- console.log("a9: " + a9);
127
-
128
- const m10 = new Map<string, JSON.Raw>();
129
- m10.set("hello", new JSON.Raw('"world"'));
130
- m10.set("pos", new JSON.Raw('{"x":1.0,"y":2.0,"z":3.0}'));
131
-
132
- const a10 = JSON.stringify(m10);
133
-
134
- console.log("a10: " + a10);
135
-
136
- const a11 = JSON.parse<JSON.Obj>(' { "x" : 3.4 , "y" : 1.2 , "z" : 8.3 } ');
137
-
138
- console.log("a11: " + JSON.stringify(a11));
139
-
140
- const a12 = JSON.parse<InnerObj<ObjWithBracketString>>('{"obj":{"data":"hello} world"}}');
141
-
142
- console.log("a12: " + JSON.stringify(a12));
143
-
144
- const a13 = JSON.stringify<JSON.Obj>(new JSON.Obj());
145
-
146
- console.log("a13: " + a13);
147
-
148
- const a14 = JSON.stringify(new Point());
149
- console.log("a14: " + a14);
150
-
151
- const a15 = JSON.parse<Point>(a14);
152
- console.log("a15: " + JSON.stringify(a15));
153
-
154
- const a16 = JSON.stringify(new NewPoint(1.0, 2.0));
155
- console.log("a16: " + a16);
156
-
157
- const a17 = JSON.parse<NewPoint>(a16);
158
- console.log("a17: " + JSON.stringify(a17));
159
-
160
- const a18 = JSON.parse<JSON.Obj[]>('[{"x":1.0,"y":2.0,"z":3.0},{"x":4.0,"y":5.0,"z":6.0},{"x":7.0,"y":8.0,"z":9.0}]');
161
- console.log("a18: " + JSON.stringify(a18));
162
-
163
- const a19 = JSON.stringify<JSON.Obj[]>(a18);
164
- console.log("a19: " + a19);
165
-
166
- const a20 = JSON.parse<JSON.Box<f64>[]>("[1.3,4.7,9.5]");
167
- console.log("a20: " + JSON.stringify(a20));
168
-
169
- const a21 = JSON.stringify<JSON.Box<f64>[]>(a20);
170
- console.log("a21: " + a21);
171
-
172
- const a22 = JSON.parse<Foo>('{"id":"0xb8","firstName":"Jairus","lastName":"Tanaka"}');
173
- console.log("a22: " + JSON.stringify(a22));
174
-
175
-
176
- @json
177
- class Foo {
178
- id: string = "";
179
- firstName: string = "";
180
- lastName: string = "";
181
- }
182
50
 
183
51
  @json
184
- class SrvInfo {
185
- accessUrl: string = "https://example.com";
186
- cardTypes: i32[] = [1, 2, 3];
187
- customService: string = "Contact us at support@example.com";
188
- invoiceApplicationStatus: i32 = 1;
189
- isCertification: bool = true;
190
- isOnlineRecharge: bool = false;
191
- loginTypes: i32[] = [0, 1]; // e.g. 0 = password, 1 = OTP
192
- record: string = "ICP 12345678";
193
- regCompanyAudit: i32 = 2;
194
- regCompanyPipeline: i32[] = [101, 102, 103];
195
- regPwdLimit: i32 = 8; // min password length
196
- serverTime: i64 = 1650000000000; // dummy timestamp
197
- srvDescription: string = "A demo service for handling customer operations.";
198
- srvHiddenMenu: string[] = ["admin", "beta"];
199
- srvHost: string = "srv.example.com";
200
- srvId: i32 = 999;
201
- srvKeywords: string[] = ["finance", "payments", "online"];
202
- srvLogoImgUrl: string = "https://example.com/logo.png";
203
- srvName: string = "ExampleService";
204
- srvPageId: i32 = 5;
205
- thirdAuthUrl: string = "https://auth.example.com";
206
- userCenterStyle: i32 = 1; // e.g. 1 = modern, 0 = legacy
52
+ class OpenAIChatOutput {
53
+ id!: string;
54
+ object!: string;
55
+ model!: string;
56
+ system_fingerprint!: string;
207
57
  }
208
-
209
- const a23 = JSON.stringify(new SrvInfo());
210
- console.log("a23: " + a23);
211
-
212
- const a24 = '{"accessUrl":"https://example.com","cardTypes":[1,2,3],"customService":"Contact us at support@example.com","invoiceApplicationStatus":1,"isCertification":true,"isOnlineRecharge":false,"loginTypes":[0,1],"record":"ICP 12345678","regCompanyAudit":2,"regCompanyPipeline":[101,102,103],"regPwdLimit":8,"serverTime":1650000000000,"srvDescription":"A demo service for handling customer operations.","srvHiddenMenu":["admin","beta"],"srvHost":"srv.example.com","srvId":999,"srvKeywords":["finance","payments","online"],"srvLogoImgUrl":"https://example.com/logo.png","srvName":"ExampleService","srvPageId":5,"thirdAuthUrl":"https://auth.example.com","userCenterStyle":1}';
213
- console.log("a25: " + (a24 == a23).toString());
214
-
215
- const a26 = JSON.parse<SrvInfo>(a23);
216
- console.log("a26: " + JSON.stringify(a26));
217
-
218
- console.log("a27: " + (JSON.stringify(a26) == a23).toString())
package/index.ts CHANGED
@@ -1 +1 @@
1
- export { JSON } from "./assembly/index";
1
+ export { JSON } from "./assembly/index";
package/lib/as-bs.ts CHANGED
@@ -16,6 +16,39 @@ export namespace bs {
16
16
  /** Proposed size of output */
17
17
  export let stackSize: usize = 0;
18
18
 
19
+ let pauseOffset: usize = 0;
20
+ let pauseStackSize: usize = 0;
21
+
22
+ /**
23
+ * Stores the state of the buffer, allowing further changes to be reset
24
+ */
25
+ // @ts-ignore: decorator
26
+ @inline export function saveState(): void {
27
+ pauseOffset = offset;
28
+ pauseStackSize = stackSize;
29
+ }
30
+
31
+ /**
32
+ * Resets the buffer to the state it was in when `pause()` was called.
33
+ * This allows for changes made after the pause to be discarded.
34
+ */
35
+ // @ts-ignore: decorator
36
+ @inline export function loadState(): void {
37
+ offset = pauseOffset;
38
+ stackSize = pauseStackSize;
39
+ }
40
+
41
+ /**
42
+ * Resets the buffer to the state it was in when `pause()` was called.
43
+ * This allows for changes made after the pause to be discarded.
44
+ */
45
+ // @ts-ignore: decorator
46
+ @inline export function resetState(): void {
47
+ offset = pauseOffset;
48
+ stackSize = pauseStackSize;
49
+ pauseOffset = 0;
50
+ }
51
+
19
52
  /**
20
53
  * Proposes that the buffer size is should be greater than or equal to the proposed size.
21
54
  * If necessary, reallocates the buffer to the exact new size.
@@ -85,6 +118,28 @@ export namespace bs {
85
118
  stackSize = 0;
86
119
  }
87
120
 
121
+ /**
122
+ * Copies the buffer's content to a new object of a specified type. Does not shrink the buffer.
123
+ * @returns The new object containing the buffer's content.
124
+ */
125
+ // @ts-ignore: Decorator valid here
126
+ @inline export function cpyOut<T>(): T {
127
+ if (pauseOffset == 0) {
128
+ const len = offset - changetype<usize>(buffer);
129
+ // @ts-ignore: exists
130
+ const _out = __new(len, idof<T>());
131
+ memory.copy(_out, changetype<usize>(buffer), len);
132
+ return changetype<T>(_out);
133
+ } else {
134
+ const len = offset - pauseOffset;
135
+ // @ts-ignore: exists
136
+ const _out = __new(len, idof<T>());
137
+ memory.copy(_out, pauseOffset, len);
138
+ bs.loadState();
139
+ return changetype<T>(_out);
140
+ }
141
+ }
142
+
88
143
  /**
89
144
  * Copies the buffer's content to a new object of a specified type.
90
145
  * @returns The new object containing the buffer's content.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "1.1.7",
3
+ "version": "1.1.9",
4
4
  "author": "Jairus Tanaka",
5
5
  "description": "The only JSON library you'll need for AssemblyScript. SIMD enabled",
6
6
  "types": "assembly/index.ts",
@@ -19,7 +19,7 @@
19
19
  "test": "bash ./run-tests.sh",
20
20
  "bench:as": "bash ./run-bench.as.sh",
21
21
  "bench:js": "bash ./run-bench.js.sh",
22
- "build:test": "rm -rf ./build/ && JSON_STRICT=true JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
22
+ "build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
23
23
  "build:test:simd": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --optimizeLevel 3 --shrinkLevel 0 --enable simd --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
24
24
  "test:wasmtime": "wasmtime ./build/test.wasm",
25
25
  "test:wasmer": "wasmer ./build/test.wasm",