json-as 0.8.6 → 0.8.7
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/.github/workflows/nodejs.yml +7 -1
- package/CHANGELOG +4 -1
- package/README.md +26 -16
- package/assembly/__tests__/deserialize.spec.ts +298 -0
- package/assembly/__tests__/serialize.spec.ts +375 -0
- package/assembly/deserialize/array/array.ts +31 -0
- package/assembly/deserialize/array/bool.ts +19 -0
- package/assembly/deserialize/array/float.ts +24 -0
- package/assembly/deserialize/array/integer.ts +24 -0
- package/assembly/deserialize/array/map.ts +27 -0
- package/assembly/deserialize/array/object.ts +27 -0
- package/assembly/deserialize/array/string.ts +29 -0
- package/assembly/deserialize/array.ts +37 -0
- package/assembly/deserialize/bool.ts +18 -0
- package/assembly/deserialize/box.ts +17 -0
- package/assembly/deserialize/date.ts +11 -0
- package/assembly/deserialize/float.ts +9 -0
- package/assembly/deserialize/integer.ts +7 -0
- package/assembly/deserialize/map.ts +182 -0
- package/assembly/deserialize/object.ts +136 -0
- package/assembly/deserialize/string.ts +88 -0
- package/assembly/index.d.ts +7 -1
- package/assembly/index.ts +129 -1
- package/assembly/serialize/array.ts +52 -0
- package/assembly/serialize/bool.ts +4 -0
- package/assembly/serialize/box.ts +10 -0
- package/assembly/serialize/date.ts +4 -0
- package/assembly/serialize/float.ts +4 -0
- package/assembly/serialize/integer.ts +5 -0
- package/assembly/serialize/map.ts +24 -0
- package/assembly/serialize/object.ts +7 -0
- package/assembly/serialize/string.ts +64 -0
- package/assembly/src/sink.ts +286 -0
- package/assembly/src/util.ts +6 -0
- package/assembly/test.ts +34 -16
- package/bench/benchmark.ts +7 -3
- package/bench.js +14 -3
- package/index.ts +1 -1
- package/package.json +6 -8
- package/transform/lib/index.js +301 -183
- package/transform/lib/index.old.js +257 -0
- package/transform/lib/types.js +17 -0
- package/transform/package.json +1 -1
- package/transform/src/index.old.ts +312 -0
- package/transform/src/index.ts +301 -215
- package/transform/tsconfig.json +2 -2
- package/tsconfig.json +94 -102
- package/assembly/__benches__/as-json.ts +0 -88
- package/assembly/__benches__/as-tral.d.ts +0 -1
- package/assembly/__tests__/as-json.spec.ts +0 -673
- package/assembly/__tests__/as-pect.d.ts +0 -1
- package/assembly/src/json.ts +0 -941
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Virtual } from "as-virtual/assembly";
|
|
2
|
+
import { containsCodePoint, unsafeCharCodeAt } from "../src/util";
|
|
3
|
+
import {
|
|
4
|
+
aCode,
|
|
5
|
+
backSlashCode,
|
|
6
|
+
colonCode,
|
|
7
|
+
commaCode,
|
|
8
|
+
eCode,
|
|
9
|
+
fCode,
|
|
10
|
+
lCode,
|
|
11
|
+
leftBraceCode,
|
|
12
|
+
leftBracketCode,
|
|
13
|
+
nCode,
|
|
14
|
+
quoteCode,
|
|
15
|
+
rCode,
|
|
16
|
+
rightBraceCode,
|
|
17
|
+
rightBracketCode,
|
|
18
|
+
sCode,
|
|
19
|
+
tCode,
|
|
20
|
+
uCode
|
|
21
|
+
} from "../src/chars";
|
|
22
|
+
import { deserializeBoolean } from "./bool";
|
|
23
|
+
import { JSON } from "..";
|
|
24
|
+
import { deserializeString } from "./string";
|
|
25
|
+
import { isSpace } from "util/string";
|
|
26
|
+
import { deserializeInteger } from "./integer";
|
|
27
|
+
import { deserializeFloat } from "./float";
|
|
28
|
+
|
|
29
|
+
// @ts-ignore: Decorator
|
|
30
|
+
@inline export function deserializeMap<T extends Map>(data: string): T {
|
|
31
|
+
|
|
32
|
+
const map: nonnull<T> = changetype<nonnull<T>>(
|
|
33
|
+
__new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const key = Virtual.createEmpty<string>();
|
|
37
|
+
let isKey = false;
|
|
38
|
+
let depth = 0;
|
|
39
|
+
let outerLoopIndex = 1;
|
|
40
|
+
for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
|
|
41
|
+
const char = unsafeCharCodeAt(data, outerLoopIndex);
|
|
42
|
+
if (char === leftBracketCode) {
|
|
43
|
+
for (
|
|
44
|
+
let arrayValueIndex = outerLoopIndex;
|
|
45
|
+
arrayValueIndex < data.length - 1;
|
|
46
|
+
arrayValueIndex++
|
|
47
|
+
) {
|
|
48
|
+
const char = unsafeCharCodeAt(data, arrayValueIndex);
|
|
49
|
+
if (char === leftBracketCode) {
|
|
50
|
+
depth++;
|
|
51
|
+
} else if (char === rightBracketCode) {
|
|
52
|
+
depth--;
|
|
53
|
+
if (depth === 0) {
|
|
54
|
+
++arrayValueIndex;
|
|
55
|
+
map.set(deserializeMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, arrayValueIndex)));
|
|
56
|
+
outerLoopIndex = arrayValueIndex;
|
|
57
|
+
isKey = false;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} else if (char === leftBraceCode) {
|
|
63
|
+
for (
|
|
64
|
+
let objectValueIndex = outerLoopIndex;
|
|
65
|
+
objectValueIndex < data.length - 1;
|
|
66
|
+
objectValueIndex++
|
|
67
|
+
) {
|
|
68
|
+
const char = unsafeCharCodeAt(data, objectValueIndex);
|
|
69
|
+
if (char === leftBraceCode) {
|
|
70
|
+
depth++;
|
|
71
|
+
} else if (char === rightBraceCode) {
|
|
72
|
+
depth--;
|
|
73
|
+
if (depth === 0) {
|
|
74
|
+
++objectValueIndex;
|
|
75
|
+
map.set(deserializeMapKey<indexof<T>>(key), JSON.parse<valueof<T>>(data.slice(outerLoopIndex, objectValueIndex)));
|
|
76
|
+
outerLoopIndex = objectValueIndex;
|
|
77
|
+
isKey = false;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} else if (char === quoteCode) {
|
|
83
|
+
let escaping = false;
|
|
84
|
+
for (
|
|
85
|
+
let stringValueIndex = ++outerLoopIndex;
|
|
86
|
+
stringValueIndex < data.length - 1;
|
|
87
|
+
stringValueIndex++
|
|
88
|
+
) {
|
|
89
|
+
const char = unsafeCharCodeAt(data, stringValueIndex);
|
|
90
|
+
if (char === backSlashCode && !escaping) {
|
|
91
|
+
escaping = true;
|
|
92
|
+
} else {
|
|
93
|
+
if (
|
|
94
|
+
char === quoteCode && !escaping
|
|
95
|
+
) {
|
|
96
|
+
if (isKey === false) {
|
|
97
|
+
// perf: we can avoid creating a new string here if the key doesn't contain any escape sequences
|
|
98
|
+
if (containsCodePoint(data, backSlashCode, outerLoopIndex, stringValueIndex)) {
|
|
99
|
+
key.reinst(deserializeString(data, outerLoopIndex - 1, stringValueIndex));
|
|
100
|
+
} else {
|
|
101
|
+
key.reinst(data, outerLoopIndex, stringValueIndex);
|
|
102
|
+
}
|
|
103
|
+
isKey = true;
|
|
104
|
+
} else {
|
|
105
|
+
if (isString<valueof<T>>()) {
|
|
106
|
+
const value = deserializeString(data, outerLoopIndex - 1, stringValueIndex);
|
|
107
|
+
map.set(deserializeMapKey<indexof<T>>(key), value);
|
|
108
|
+
}
|
|
109
|
+
isKey = false;
|
|
110
|
+
}
|
|
111
|
+
outerLoopIndex = ++stringValueIndex;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
escaping = false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} else if (
|
|
118
|
+
char == nCode &&
|
|
119
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
|
|
120
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
|
|
121
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === lCode) {
|
|
122
|
+
if (isNullable<valueof<T>>()) {
|
|
123
|
+
map.set(deserializeMapKey<indexof<T>>(key), null);
|
|
124
|
+
}
|
|
125
|
+
isKey = false;
|
|
126
|
+
} else if (
|
|
127
|
+
char === tCode &&
|
|
128
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === rCode &&
|
|
129
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === uCode &&
|
|
130
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
|
|
131
|
+
) {
|
|
132
|
+
if (isBoolean<valueof<T>>()) {
|
|
133
|
+
map.set(deserializeMapKey<indexof<T>>(key), true);
|
|
134
|
+
}
|
|
135
|
+
isKey = false;
|
|
136
|
+
} else if (
|
|
137
|
+
char === fCode &&
|
|
138
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === aCode &&
|
|
139
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === lCode &&
|
|
140
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === sCode &&
|
|
141
|
+
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
|
|
142
|
+
) {
|
|
143
|
+
if (isBoolean<valueof<T>>()) {
|
|
144
|
+
map.set(deserializeMapKey<indexof<T>>(key), false);
|
|
145
|
+
}
|
|
146
|
+
isKey = false;
|
|
147
|
+
} else if ((char >= 48 && char <= 57) || char === 45) {
|
|
148
|
+
let numberValueIndex = ++outerLoopIndex;
|
|
149
|
+
for (; numberValueIndex < data.length; numberValueIndex++) {
|
|
150
|
+
const char = unsafeCharCodeAt(data, numberValueIndex);
|
|
151
|
+
if (char === colonCode || char === commaCode || char === rightBraceCode || isSpace(char)) {
|
|
152
|
+
if (isInteger<valueof<T>>()) {
|
|
153
|
+
map.set(deserializeMapKey<indexof<T>>(key), deserializeInteger<valueof<T>>(data.slice(outerLoopIndex - 1, numberValueIndex)));
|
|
154
|
+
} else if (isFloat<valueof<T>>()) {
|
|
155
|
+
map.set(deserializeMapKey<indexof<T>>(key), deserializeFloat<valueof<T>>(data.slice(outerLoopIndex - 1, numberValueIndex)));
|
|
156
|
+
}
|
|
157
|
+
outerLoopIndex = numberValueIndex;
|
|
158
|
+
isKey = false;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return map;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//@ts-ignore: Decorator
|
|
169
|
+
@inline function deserializeMapKey<T>(key: Virtual<string>): T {
|
|
170
|
+
const k = key.copyOut();
|
|
171
|
+
if (isString<T>()) {
|
|
172
|
+
return k as T;
|
|
173
|
+
} else if (isBoolean<T>()) {
|
|
174
|
+
return deserializeBoolean(k) as T;
|
|
175
|
+
} else if (isInteger<T>()) {
|
|
176
|
+
return deserializeInteger<T>(k);
|
|
177
|
+
} else if (isFloat<T>()) {
|
|
178
|
+
return deserializeFloat<T>(k);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
throw new Error(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof<T>()}`);
|
|
182
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { containsCodePoint, unsafeCharCodeAt } from "../src/util";
|
|
2
|
+
import { aCode, backSlashCode, commaCode, eCode, fCode, lCode, leftBraceCode, leftBracketCode, nCode, quoteCode, rCode, rightBraceCode, rightBracketCode, sCode, tCode, uCode } from "../src/chars";
|
|
3
|
+
import { isSpace } from "util/string";
|
|
4
|
+
|
|
5
|
+
// @ts-ignore: Decorator
|
|
6
|
+
@inline export function deserializeObject<T>(data: string): T {
|
|
7
|
+
const schema: nonnull<T> = changetype<nonnull<T>>(
|
|
8
|
+
__new(offsetof<nonnull<T>>(), idof<nonnull<T>>())
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
schema.__INITIALIZE();
|
|
13
|
+
|
|
14
|
+
let key_start: i32 = 0;
|
|
15
|
+
let key_end: i32 = 0;
|
|
16
|
+
let isKey = false;
|
|
17
|
+
let depth = 0;
|
|
18
|
+
let outerLoopIndex = 1;
|
|
19
|
+
for (; outerLoopIndex < data.length - 1; outerLoopIndex++) {
|
|
20
|
+
const char = unsafeCharCodeAt(data, outerLoopIndex);
|
|
21
|
+
if (char === leftBracketCode) {
|
|
22
|
+
for (
|
|
23
|
+
let arrayValueIndex = outerLoopIndex;
|
|
24
|
+
arrayValueIndex < data.length - 1;
|
|
25
|
+
arrayValueIndex++
|
|
26
|
+
) {
|
|
27
|
+
const char = unsafeCharCodeAt(data, arrayValueIndex);
|
|
28
|
+
if (char === leftBracketCode) {
|
|
29
|
+
depth++;
|
|
30
|
+
} else if (char === rightBracketCode) {
|
|
31
|
+
depth--;
|
|
32
|
+
if (depth === 0) {
|
|
33
|
+
++arrayValueIndex;
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
schema.__DESERIALIZE(data, key_start, key_end, outerLoopIndex, arrayValueIndex);
|
|
36
|
+
outerLoopIndex = arrayValueIndex;
|
|
37
|
+
isKey = false;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} else if (char === leftBraceCode) {
|
|
43
|
+
for (
|
|
44
|
+
let objectValueIndex = outerLoopIndex;
|
|
45
|
+
objectValueIndex < data.length - 1;
|
|
46
|
+
objectValueIndex++
|
|
47
|
+
) {
|
|
48
|
+
const char = unsafeCharCodeAt(data, objectValueIndex);
|
|
49
|
+
if (char === leftBraceCode) {
|
|
50
|
+
depth++;
|
|
51
|
+
} else if (char === rightBraceCode) {
|
|
52
|
+
depth--;
|
|
53
|
+
if (depth === 0) {
|
|
54
|
+
++objectValueIndex;
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
schema.__DESERIALIZE(data, key_start, key_end, outerLoopIndex, objectValueIndex);
|
|
57
|
+
outerLoopIndex = objectValueIndex;
|
|
58
|
+
isKey = false;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} else if (char === quoteCode) {
|
|
64
|
+
let escaping = false;
|
|
65
|
+
for (
|
|
66
|
+
let stringValueIndex = ++outerLoopIndex;
|
|
67
|
+
stringValueIndex < data.length - 1;
|
|
68
|
+
stringValueIndex++
|
|
69
|
+
) {
|
|
70
|
+
const char = unsafeCharCodeAt(data, stringValueIndex);
|
|
71
|
+
if (char === backSlashCode && !escaping) {
|
|
72
|
+
escaping = true;
|
|
73
|
+
} else {
|
|
74
|
+
if (char === quoteCode && !escaping) {
|
|
75
|
+
if (isKey === false) {
|
|
76
|
+
key_start = outerLoopIndex;
|
|
77
|
+
key_end = stringValueIndex;
|
|
78
|
+
isKey = true;
|
|
79
|
+
} else {
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
schema.__DESERIALIZE(data, key_start, key_end, outerLoopIndex - 1, stringValueIndex + 1);
|
|
82
|
+
isKey = false;
|
|
83
|
+
}
|
|
84
|
+
outerLoopIndex = ++stringValueIndex;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
escaping = false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} else if (
|
|
91
|
+
char == nCode &&
|
|
92
|
+
unsafeCharCodeAt(data, outerLoopIndex + 1) === uCode &&
|
|
93
|
+
unsafeCharCodeAt(data, outerLoopIndex + 2) === lCode &&
|
|
94
|
+
unsafeCharCodeAt(data, outerLoopIndex + 3) === lCode
|
|
95
|
+
) {
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
schema.__DESERIALIZE(data, key_start, key_end, outerLoopIndex, outerLoopIndex + 4);
|
|
98
|
+
outerLoopIndex += 3;
|
|
99
|
+
isKey = false;
|
|
100
|
+
} else if (
|
|
101
|
+
char === tCode &&
|
|
102
|
+
unsafeCharCodeAt(data, outerLoopIndex + 1) === rCode &&
|
|
103
|
+
unsafeCharCodeAt(data, outerLoopIndex + 2) === uCode &&
|
|
104
|
+
unsafeCharCodeAt(data, outerLoopIndex + 3) === eCode
|
|
105
|
+
) {
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
schema.__DESERIALIZE(data, key_start, key_end, outerLoopIndex, outerLoopIndex + 4);
|
|
108
|
+
outerLoopIndex += 3;
|
|
109
|
+
isKey = false;
|
|
110
|
+
} else if (
|
|
111
|
+
char === fCode &&
|
|
112
|
+
unsafeCharCodeAt(data, outerLoopIndex + 1) === aCode &&
|
|
113
|
+
unsafeCharCodeAt(data, outerLoopIndex + 2) === lCode &&
|
|
114
|
+
unsafeCharCodeAt(data, outerLoopIndex + 3) === sCode &&
|
|
115
|
+
unsafeCharCodeAt(data, outerLoopIndex + 4) === eCode
|
|
116
|
+
) {
|
|
117
|
+
// @ts-ignore
|
|
118
|
+
schema.__DESERIALIZE(data, key_start, key_end, outerLoopIndex, outerLoopIndex + 5);
|
|
119
|
+
outerLoopIndex += 4;
|
|
120
|
+
isKey = false;
|
|
121
|
+
} else if ((char >= 48 && char <= 57) || char === 45) {
|
|
122
|
+
let numberValueIndex = ++outerLoopIndex;
|
|
123
|
+
for (; numberValueIndex < data.length; numberValueIndex++) {
|
|
124
|
+
const char = unsafeCharCodeAt(data, numberValueIndex);
|
|
125
|
+
if (char === commaCode || char === rightBraceCode || isSpace(char)) {
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
schema.__DESERIALIZE(data, key_start, key_end, outerLoopIndex - 1, numberValueIndex);
|
|
128
|
+
outerLoopIndex = numberValueIndex;
|
|
129
|
+
isKey = false;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return schema;
|
|
136
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bCode,
|
|
3
|
+
backSlashCode,
|
|
4
|
+
backspaceCode,
|
|
5
|
+
carriageReturnCode,
|
|
6
|
+
fCode,
|
|
7
|
+
formFeedCode,
|
|
8
|
+
forwardSlashCode,
|
|
9
|
+
nCode,
|
|
10
|
+
newLineCode,
|
|
11
|
+
quoteCode,
|
|
12
|
+
rCode,
|
|
13
|
+
tCode,
|
|
14
|
+
tabCode,
|
|
15
|
+
uCode
|
|
16
|
+
} from "../src/chars";
|
|
17
|
+
import { Sink } from "../src/sink";
|
|
18
|
+
import { unsafeCharCodeAt } from "../src/util";
|
|
19
|
+
|
|
20
|
+
// @ts-ignore: Decorator
|
|
21
|
+
@inline export function deserializeString(data: string, start: i32 = 0, end: i32 = 0): string {
|
|
22
|
+
end = end || data.length - 1;
|
|
23
|
+
let result = Sink.withCapacity(end - start - 1);
|
|
24
|
+
let last = start + 1;
|
|
25
|
+
for (let i = last; i < end; i++) {
|
|
26
|
+
if (unsafeCharCodeAt(data, i) !== backSlashCode) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const char = unsafeCharCodeAt(data, ++i);
|
|
30
|
+
result.write(data, last, i - 1);
|
|
31
|
+
switch (char) {
|
|
32
|
+
case quoteCode: {
|
|
33
|
+
result.writeCodePoint(quoteCode);
|
|
34
|
+
last = i + 1;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case backSlashCode: {
|
|
38
|
+
result.writeCodePoint(backSlashCode);
|
|
39
|
+
last = i + 1;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case forwardSlashCode: {
|
|
43
|
+
result.writeCodePoint(forwardSlashCode);
|
|
44
|
+
last = i + 1;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case bCode: {
|
|
48
|
+
result.writeCodePoint(backspaceCode);
|
|
49
|
+
last = i + 1;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case fCode: {
|
|
53
|
+
result.writeCodePoint(formFeedCode);
|
|
54
|
+
last = i + 1;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case nCode: {
|
|
58
|
+
result.writeCodePoint(newLineCode);
|
|
59
|
+
last = i + 1;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case rCode: {
|
|
63
|
+
result.writeCodePoint(carriageReturnCode);
|
|
64
|
+
last = i + 1;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case tCode: {
|
|
68
|
+
result.writeCodePoint(tabCode);
|
|
69
|
+
last = i + 1;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case uCode: {
|
|
73
|
+
const code = u16.parse(data.slice(i + 1, i + 5), 16);
|
|
74
|
+
result.writeCodePoint(code);
|
|
75
|
+
i += 4;
|
|
76
|
+
last = i + 1;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
default: {
|
|
80
|
+
throw new Error(`JSON: Cannot parse "${data}" as string. Invalid escape sequence: \\${data.charAt(i)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (end > last) {
|
|
85
|
+
result.write(data, last, end);
|
|
86
|
+
}
|
|
87
|
+
return result.toString()
|
|
88
|
+
}
|
package/assembly/index.d.ts
CHANGED
|
@@ -13,10 +13,16 @@ declare function serializable(target: any): void;
|
|
|
13
13
|
*/
|
|
14
14
|
declare function alias(name: string): Function;
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Property decorator that allows omits a field, making it be ignored.
|
|
18
|
+
*/
|
|
19
|
+
declare function omit(): Function;
|
|
20
|
+
|
|
21
|
+
|
|
16
22
|
/**
|
|
17
23
|
* Property decorator that allows a field to be omitted when equal to an Expression.
|
|
18
24
|
*/
|
|
19
|
-
declare function
|
|
25
|
+
declare function omitif(condition: string): Function;
|
|
20
26
|
|
|
21
27
|
/**
|
|
22
28
|
* Property decorator that allows a field to be omitted when a property is null.
|
package/assembly/index.ts
CHANGED
|
@@ -1,3 +1,131 @@
|
|
|
1
1
|
/// <reference path="./index.d.ts" />
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { Box } from "as-container/assembly";
|
|
4
|
+
|
|
5
|
+
import { serializeString } from "./serialize/string";
|
|
6
|
+
import { serializeBool } from "./serialize/bool";
|
|
7
|
+
import { serializeBox } from "./serialize/box";
|
|
8
|
+
import { serializeInteger } from "./serialize/integer";
|
|
9
|
+
import { serializeFloat } from "./serialize/float";
|
|
10
|
+
import { serializeObject } from "./serialize/object";
|
|
11
|
+
import { serializeDate } from "./serialize/date";
|
|
12
|
+
import { serializeArray } from "./serialize/array";
|
|
13
|
+
import { serializeMap } from "./serialize/map";
|
|
14
|
+
import { deserializeBoolean } from "./deserialize/bool";
|
|
15
|
+
import { deserializeArray } from "./deserialize/array";
|
|
16
|
+
import { deserializeFloat } from "./deserialize/float";
|
|
17
|
+
import { deserializeBox } from "./deserialize/box";
|
|
18
|
+
import { deserializeObject } from "./deserialize/object";
|
|
19
|
+
import { deserializeMap } from "./deserialize/map";
|
|
20
|
+
import { deserializeDate } from "./deserialize/date";
|
|
21
|
+
import { nullWord } from "./src/chars";
|
|
22
|
+
import { deserializeInteger } from "./deserialize/integer";
|
|
23
|
+
import { deserializeString } from "./deserialize/string";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* JSON Encoder/Decoder for AssemblyScript
|
|
27
|
+
*/
|
|
28
|
+
export namespace JSON {
|
|
29
|
+
/**
|
|
30
|
+
* Stringifies valid JSON data.
|
|
31
|
+
* ```js
|
|
32
|
+
* JSON.stringify<T>(data)
|
|
33
|
+
* ```
|
|
34
|
+
* @param data T
|
|
35
|
+
* @returns string
|
|
36
|
+
*/
|
|
37
|
+
// @ts-ignore: Decorator
|
|
38
|
+
@inline export function stringify<T>(data: T): string {
|
|
39
|
+
if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
|
|
40
|
+
return nullWord;
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
} else if (isString<T>()) {
|
|
43
|
+
return serializeString(data as string);
|
|
44
|
+
} else if (isBoolean<T>()) {
|
|
45
|
+
return serializeBool(data as bool);
|
|
46
|
+
} else if (data instanceof Box) {
|
|
47
|
+
return serializeBox(data);
|
|
48
|
+
} else if (isInteger<T>()) {
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
return serializeInteger<T>(data);
|
|
51
|
+
} else if (isFloat<T>(data)) {
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
return serializeFloat<T>(data);
|
|
54
|
+
// @ts-ignore: Function is generated by transform
|
|
55
|
+
} else if (isDefined(data.__SERIALIZE)) {
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
return serializeObject(data);
|
|
58
|
+
} else if (data instanceof Date) {
|
|
59
|
+
return serializeDate(data);
|
|
60
|
+
} else if (data instanceof Array) {
|
|
61
|
+
return serializeArray(data);
|
|
62
|
+
} else if (data instanceof Map) {
|
|
63
|
+
return serializeMap(data);
|
|
64
|
+
} else {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Could not serialize data of type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parses valid JSON strings into their original format.
|
|
72
|
+
* ```js
|
|
73
|
+
* JSON.parse<T>(data)
|
|
74
|
+
* ```
|
|
75
|
+
* @param data string
|
|
76
|
+
* @returns T
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
// @ts-ignore: Decorator
|
|
80
|
+
@inline export function parse<T>(data: string): T {
|
|
81
|
+
if (isString<T>()) {
|
|
82
|
+
// @ts-ignore
|
|
83
|
+
return deserializeString(data);
|
|
84
|
+
} else if (isBoolean<T>()) {
|
|
85
|
+
return deserializeBoolean(data) as T;
|
|
86
|
+
} else if (isInteger<T>()) {
|
|
87
|
+
return deserializeInteger<T>(data);
|
|
88
|
+
} else if (isFloat<T>()) {
|
|
89
|
+
return deserializeFloat<T>(data);
|
|
90
|
+
} else if (isArray<T>()) {
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
return deserializeArray<T>(data);
|
|
93
|
+
}
|
|
94
|
+
let type: nonnull<T> = changetype<nonnull<T>>(__new(offsetof<nonnull<T>>(), idof<nonnull<T>>()));
|
|
95
|
+
if (type instanceof Box) {
|
|
96
|
+
return deserializeBox<T>(data);
|
|
97
|
+
} else if (isNullable<T>() && data == nullWord) {
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
return null;
|
|
100
|
+
// @ts-ignore
|
|
101
|
+
} else if (isDefined(type.__DESERIALIZE)) {
|
|
102
|
+
return deserializeObject<T>(data.trimStart());
|
|
103
|
+
} else if (type instanceof Map) {
|
|
104
|
+
return deserializeMap<T>(data.trimStart());
|
|
105
|
+
} else if (type instanceof Date) {
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
return deserializeDate(data);
|
|
108
|
+
} else {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Could not deserialize data ${data} to type ${nameof<T>()}. Make sure to add the correct decorators to classes.`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// @ts-ignore: Decorator
|
|
117
|
+
@global @inline function __parseObjectValue<T>(data: string, initializeDefaultValues: boolean): T {
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
if (isString<T>()) return data;
|
|
120
|
+
return JSON.parse<T>(data, initializeDefaultValues);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Dirty fix
|
|
124
|
+
// @ts-ignore: Decorator
|
|
125
|
+
@global @inline function __SERIALIZE<T>(data: T): string {
|
|
126
|
+
return JSON.stringify(data);
|
|
127
|
+
}
|
|
128
|
+
// @ts-ignore: Decorator
|
|
129
|
+
@global @inline function __DESERIALIZE<T>(data: string): T {
|
|
130
|
+
return JSON.parse<T>(data);
|
|
131
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { JSON } from "..";
|
|
2
|
+
import {
|
|
3
|
+
commaCode,
|
|
4
|
+
commaWord,
|
|
5
|
+
emptyArrayWord,
|
|
6
|
+
leftBracketWord,
|
|
7
|
+
rightBracketCode,
|
|
8
|
+
rightBracketWord
|
|
9
|
+
} from "../src/chars";
|
|
10
|
+
import { Sink } from "../src/sink";
|
|
11
|
+
import { serializeString } from "./string";
|
|
12
|
+
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
@inline export function serializeArray<T extends any[]>(data: T): string {
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
if (data.length == 0) {
|
|
17
|
+
return emptyArrayWord;
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
} else if (isString<valueof<T>>()) {
|
|
20
|
+
let result = leftBracketWord;
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
for (let i = 0; i < data.length - 1; i++) {
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
result += serializeString(unchecked(data[i]));
|
|
25
|
+
result += commaWord;
|
|
26
|
+
}
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
result += serializeString(unchecked(data[data.length - 1]));
|
|
29
|
+
result += rightBracketWord;
|
|
30
|
+
return result;
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
} else if (isBoolean<valueof<T>>()) {
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
return leftBracketWord + data.join(commaWord) + rightBracketWord;
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
} else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
return leftBracketWord + data.join(commaWord) + rightBracketWord;
|
|
39
|
+
} else {
|
|
40
|
+
let result = Sink.fromString(leftBracketWord);
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
for (let i = 0; i < data.length - 1; i++) {
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
result.write(JSON.stringify(unchecked(data[i])));
|
|
45
|
+
result.writeCodePoint(commaCode);
|
|
46
|
+
}
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
result.write(JSON.stringify(unchecked(data[data.length - 1])));
|
|
49
|
+
result.writeCodePoint(rightBracketCode);
|
|
50
|
+
return result.toString();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { nullWord } from "../src/chars";
|
|
2
|
+
import { JSON } from "..";
|
|
3
|
+
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
@inline export function serializeBox<T extends Box<any>>(data: T): string {
|
|
6
|
+
if (isNullable<T>() && changetype<usize>(data) == <usize>0) {
|
|
7
|
+
return nullWord;
|
|
8
|
+
}
|
|
9
|
+
return JSON.stringify(data.unwrap());
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { colonCode, commaCode, leftBraceWord, rightBraceCode } from "../src/chars";
|
|
2
|
+
import { JSON } from "..";
|
|
3
|
+
import { Sink } from "../src/sink";
|
|
4
|
+
import { serializeString } from "./string";
|
|
5
|
+
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
@inline export function serializeMap<T extends Map<any, any>>(data: T): string {
|
|
8
|
+
let result = Sink.fromString(leftBraceWord);
|
|
9
|
+
let keys = data.keys();
|
|
10
|
+
let values = data.values();
|
|
11
|
+
const end = data.size - 1;
|
|
12
|
+
for (let i = 0; i < end; i++) {
|
|
13
|
+
result.write(serializeString(unchecked(keys[i]).toString()));
|
|
14
|
+
result.writeCodePoint(colonCode);
|
|
15
|
+
result.write(JSON.stringify(unchecked(values[i])));
|
|
16
|
+
result.writeCodePoint(commaCode);
|
|
17
|
+
}
|
|
18
|
+
result.write(serializeString(unchecked(keys[end]).toString()));
|
|
19
|
+
result.writeCodePoint(colonCode);
|
|
20
|
+
result.write(JSON.stringify(unchecked(values[end])));
|
|
21
|
+
|
|
22
|
+
result.writeCodePoint(rightBraceCode);
|
|
23
|
+
return result.toString();
|
|
24
|
+
}
|