Comparing version 0.9.21 to 0.9.22
@@ -5,17 +5,17 @@ import { JSON } from "json-as"; | ||
describe("Should serialize booleans", () => { | ||
expect(JSON.stringify<bool>(true)).toBe("true"); | ||
expect(JSON.stringify<bool>(true)).toBe("true"); | ||
expect(JSON.stringify<bool>(false)).toBe("false"); | ||
expect(JSON.stringify<bool>(false)).toBe("false"); | ||
expect(JSON.stringify<boolean>(true)).toBe("true"); | ||
expect(JSON.stringify<boolean>(true)).toBe("true"); | ||
expect(JSON.stringify<boolean>(false)).toBe("false"); | ||
expect(JSON.stringify<boolean>(false)).toBe("false"); | ||
}); | ||
describe("Should deserialize booleans", () => { | ||
expect(JSON.parse<boolean>("true")).toBe(true); | ||
expect(JSON.parse<boolean>("true")).toBe(true); | ||
expect(JSON.parse<boolean>("false")).toBe(false); | ||
expect(JSON.parse<boolean>("false")).toBe(false); | ||
}); | ||
run(); | ||
run(); |
@@ -5,49 +5,49 @@ import { JSON } from "json-as"; | ||
describe("Should serialize floats", () => { | ||
expect(JSON.stringify<f64>(7.23)).toBe("7.23"); | ||
expect(JSON.stringify<f64>(7.23)).toBe("7.23"); | ||
expect(JSON.stringify<f64>(10e2)).toBe("1000.0"); | ||
expect(JSON.stringify<f64>(10e2)).toBe("1000.0"); | ||
expect(JSON.stringify<f64>(123456e-5)).toBe("1.23456"); | ||
expect(JSON.stringify<f64>(123456e-5)).toBe("1.23456"); | ||
expect(JSON.stringify<f64>(0.0)).toBe("0.0"); | ||
expect(JSON.stringify<f64>(0.0)).toBe("0.0"); | ||
expect(JSON.stringify<f64>(-7.23)).toBe("-7.23"); | ||
expect(JSON.stringify<f64>(-7.23)).toBe("-7.23"); | ||
expect(JSON.stringify<f64>(1e-6)).toBe("0.000001"); | ||
expect(JSON.stringify<f64>(1e-6)).toBe("0.000001"); | ||
expect(JSON.stringify<f64>(1e-7)).toBe("1e-7"); | ||
expect(JSON.stringify<f64>(1e-7)).toBe("1e-7"); | ||
expect(JSON.parse<f64>("1E-7")).toBe(1e-7); | ||
expect(JSON.parse<f64>("1E-7")).toBe(1e-7); | ||
expect(JSON.stringify<f64>(1e20)).toBe("100000000000000000000.0"); | ||
expect(JSON.stringify<f64>(1e20)).toBe("100000000000000000000.0"); | ||
expect(JSON.stringify<f64>(1e21)).toBe("1e+21"); | ||
expect(JSON.stringify<f64>(1e21)).toBe("1e+21"); | ||
expect(JSON.parse<f64>("1E+21")).toBe(1e21); | ||
expect(JSON.parse<f64>("1E+21")).toBe(1e21); | ||
expect(JSON.parse<f64>("1e21")).toBe(1e21); | ||
expect(JSON.parse<f64>("1e21")).toBe(1e21); | ||
expect(JSON.parse<f64>("1E21")).toBe(1e21); | ||
expect(JSON.parse<f64>("1E21")).toBe(1e21); | ||
}); | ||
describe("Should deserialize floats", () => { | ||
expect(JSON.parse<f64>("7.23")).toBe(7.23); | ||
expect(JSON.parse<f64>("7.23")).toBe(7.23); | ||
expect(JSON.parse<f64>("1000.0")).toBe(1000.0); | ||
expect(JSON.parse<f64>("1000.0")).toBe(1000.0); | ||
expect(JSON.parse<f64>("1.23456")).toBe(1.23456); | ||
expect(JSON.parse<f64>("1.23456")).toBe(1.23456); | ||
expect(JSON.parse<f64>("0.0")).toBe(0.0); | ||
expect(JSON.parse<f64>("0.0")).toBe(0.0); | ||
expect(JSON.parse<f64>("-7.23")).toBe(-7.23); | ||
expect(JSON.parse<f64>("-7.23")).toBe(-7.23); | ||
expect(JSON.parse<f64>("0.000001")).toBe(0.000001); | ||
expect(JSON.parse<f64>("0.000001")).toBe(0.000001); | ||
expect(JSON.parse<f64>("1e-7")).toBe(1e-7); | ||
expect(JSON.parse<f64>("1e-7")).toBe(1e-7); | ||
expect(JSON.parse<f64>("100000000000000000000.0")).toBe(1e20); | ||
expect(JSON.parse<f64>("100000000000000000000.0")).toBe(1e20); | ||
expect(JSON.parse<f64>("1e+21")).toBe(1e21); | ||
expect(JSON.parse<f64>("1e+21")).toBe(1e21); | ||
}); | ||
run(); | ||
run(); |
@@ -5,25 +5,25 @@ import { JSON } from "json-as"; | ||
describe("Should serialize integers", () => { | ||
expect(JSON.stringify(0)).toBe("0"); | ||
expect(JSON.stringify(0)).toBe("0"); | ||
expect(JSON.stringify<u32>(100)).toBe("100"); | ||
expect(JSON.stringify<u32>(100)).toBe("100"); | ||
expect(JSON.stringify<u64>(101)).toBe("101"); | ||
expect(JSON.stringify<u64>(101)).toBe("101"); | ||
expect(JSON.stringify<i32>(-100)).toBe("-100"); | ||
expect(JSON.stringify<i32>(-100)).toBe("-100"); | ||
expect(JSON.stringify<i64>(-101)).toBe("-101"); | ||
expect(JSON.stringify<i64>(-101)).toBe("-101"); | ||
}); | ||
describe("Should deserialize integers", () => { | ||
expect(JSON.parse<i32>("0")).toBe(<i32>0); | ||
expect(JSON.parse<i32>("0")).toBe(<i32>0); | ||
expect(JSON.parse<u32>("100")).toBe(<u32>100); | ||
expect(JSON.parse<u32>("100")).toBe(<u32>100); | ||
expect(JSON.parse<u64>("101")).toBe(<u64>101); | ||
expect(JSON.parse<u64>("101")).toBe(<u64>101); | ||
expect(JSON.parse<i32>("-100")).toBe(<i32>-100); | ||
expect(JSON.parse<i32>("-100")).toBe(<i32>-100); | ||
expect(JSON.parse<i64>("-101")).toBe(<i64>-101); | ||
expect(JSON.parse<i64>("-101")).toBe(<i64>-101); | ||
}); | ||
run(); | ||
run(); |
import { JSON } from "json-as"; | ||
import { describe, expect, run } from "as-test/assembly"; | ||
run(); | ||
run(); |
@@ -5,45 +5,21 @@ import { JSON } from "json-as"; | ||
describe("Should serialize strings", () => { | ||
expect(JSON.stringify("abcdefg")).toBe('"abcdefg"'); | ||
expect(JSON.stringify("abcdefg")).toBe('"abcdefg"'); | ||
expect(JSON.stringify('st"ring" w""ith quotes"')).toBe( | ||
'"st\\"ring\\" w\\"\\"ith quotes\\""', | ||
); | ||
expect(JSON.stringify('st"ring" w""ith quotes"')).toBe('"st\\"ring\\" w\\"\\"ith quotes\\""'); | ||
expect( | ||
JSON.stringify('string "with random spa\nces and \nnewlines\n\n\n'), | ||
).toBe('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"'); | ||
expect(JSON.stringify('string "with random spa\nces and \nnewlines\n\n\n')).toBe('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"'); | ||
expect( | ||
JSON.stringify( | ||
'string with colon : comma , brace [ ] bracket { } and quote " and other quote \\"', | ||
), | ||
).toBe( | ||
'"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\\\\\""', | ||
); | ||
expect(JSON.stringify('string with colon : comma , brace [ ] bracket { } and quote " and other quote \\"')).toBe('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\\\\\""'); | ||
}); | ||
describe("Should deserialize strings", () => { | ||
expect(JSON.parse<string>('"abcdefg"')).toBe("abcdefg"); | ||
expect( | ||
JSON.parse<string>( | ||
'"\\"st\\\\\\"ring\\\\\\" w\\\\\\"\\\\\\"ith quotes\\\\\\"\\""', | ||
), | ||
).toBe('"st\\"ring\\" w\\"\\"ith quotes\\""'); | ||
expect( | ||
JSON.parse<string>( | ||
'"\\"string \\\\\\"with random spa\\\\nces and \\\\nnewlines\\\\n\\\\n\\\\n\\""', | ||
), | ||
).toBe('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"'); | ||
expect( | ||
JSON.parse<string>( | ||
'"\\"string with colon : comma , brace [ ] bracket { } and quote \\\\\\" and other quote \\\\\\\\\\"\\""', | ||
), | ||
).toBe( | ||
'"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\\\""', | ||
); | ||
}); | ||
expect(JSON.parse<string>('"abcdefg"')).toBe("abcdefg"); | ||
run(); | ||
expect(JSON.parse<string>('"\\"st\\\\\\"ring\\\\\\" w\\\\\\"\\\\\\"ith quotes\\\\\\"\\""')).toBe('"st\\"ring\\" w\\"\\"ith quotes\\""'); | ||
expect(JSON.parse<string>('"\\"string \\\\\\"with random spa\\\\nces and \\\\nnewlines\\\\n\\\\n\\\\n\\""')).toBe('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"'); | ||
expect(JSON.parse<string>('"\\"string with colon : comma , brace [ ] bracket { } and quote \\\\\\" and other quote \\\\\\\\\\"\\""')).toBe('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\\\""'); | ||
}); | ||
run(); |
import { JSON } from "json-as"; | ||
import { describe, expect, run } from "as-test/assembly"; | ||
import { | ||
DerivedObject, | ||
Null, | ||
ObjWithStrangeKey, | ||
ObjectWithFloat, | ||
OmitIf, | ||
Player, | ||
Vec3, | ||
} from "./types"; | ||
import { DerivedObject, Null, ObjWithStrangeKey, ObjectWithFloat, OmitIf, Player, Vec3 } from "./types"; | ||
@@ -28,19 +20,11 @@ describe("Should serialize class inheritance", () => { | ||
expect(JSON.stringify<i32[]>([0, 100, 101, -100, -101])).toBe( | ||
"[0,100,101,-100,-101]", | ||
); | ||
expect(JSON.stringify<i32[]>([0, 100, 101, -100, -101])).toBe("[0,100,101,-100,-101]"); | ||
expect(JSON.stringify<i64[]>([0, 100, 101, -100, -101])).toBe( | ||
"[0,100,101,-100,-101]", | ||
); | ||
expect(JSON.stringify<i64[]>([0, 100, 101, -100, -101])).toBe("[0,100,101,-100,-101]"); | ||
}); | ||
describe("Should serialize float arrays", () => { | ||
expect( | ||
JSON.stringify<f64[]>([7.23, 10e2, 10e2, 123456e-5, 123456e-5, 0.0, 7.23]), | ||
).toBe("[7.23,1000.0,1000.0,1.23456,1.23456,0.0,7.23]"); | ||
expect(JSON.stringify<f64[]>([7.23, 10e2, 10e2, 123456e-5, 123456e-5, 0.0, 7.23])).toBe("[7.23,1000.0,1000.0,1.23456,1.23456,0.0,7.23]"); | ||
expect(JSON.stringify<f64[]>([1e21, 1e22, 1e-7, 1e-8, 1e-9])).toBe( | ||
"[1e+21,1e+22,1e-7,1e-8,1e-9]", | ||
); | ||
expect(JSON.stringify<f64[]>([1e21, 1e22, 1e-7, 1e-8, 1e-9])).toBe("[1e+21,1e+22,1e-7,1e-8,1e-9]"); | ||
}); | ||
@@ -55,27 +39,11 @@ | ||
describe("Should serialize string arrays", () => { | ||
expect( | ||
JSON.stringify<string[]>([ | ||
'string "with random spa\nces and \nnewlines\n\n\n', | ||
]), | ||
).toBe('["string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"]'); | ||
expect(JSON.stringify<string[]>(['string "with random spa\nces and \nnewlines\n\n\n'])).toBe('["string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"]'); | ||
}); | ||
describe("Should serialize nested integer arrays", () => { | ||
expect(JSON.stringify<i64[][]>([[100, 101], [-100, -101], [0]])).toBe( | ||
"[[100,101],[-100,-101],[0]]", | ||
); | ||
expect(JSON.stringify<i64[][]>([[100, 101], [-100, -101], [0]])).toBe("[[100,101],[-100,-101],[0]]"); | ||
}); | ||
describe("Should serialize nested float arrays", () => { | ||
expect( | ||
JSON.stringify<f64[][]>([ | ||
[7.23], | ||
[10e2], | ||
[10e2], | ||
[123456e-5], | ||
[123456e-5], | ||
[0.0], | ||
[7.23], | ||
]), | ||
).toBe("[[7.23],[1000.0],[1000.0],[1.23456],[1.23456],[0.0],[7.23]]"); | ||
expect(JSON.stringify<f64[][]>([[7.23], [10e2], [10e2], [123456e-5], [123456e-5], [0.0], [7.23]])).toBe("[[7.23],[1000.0],[1000.0],[1.23456],[1.23456],[0.0],[7.23]]"); | ||
}); | ||
@@ -86,5 +54,3 @@ | ||
expect(JSON.stringify<boolean[][]>([[true], [false]])).toBe( | ||
"[[true],[false]]", | ||
); | ||
expect(JSON.stringify<boolean[][]>([[true], [false]])).toBe("[[true],[false]]"); | ||
}); | ||
@@ -131,23 +97,15 @@ | ||
}), | ||
).toBe( | ||
'{"firstName":"Emmet","lastName":"West","lastActive":[8,27,2022],"age":23,"pos":{"x":3.4,"y":1.2,"z":8.3},"isVerified":true}', | ||
); | ||
).toBe('{"firstName":"Emmet","lastName":"West","lastActive":[8,27,2022],"age":23,"pos":{"x":3.4,"y":1.2,"z":8.3},"isVerified":true}'); | ||
expect(JSON.stringify<ObjectWithFloat>({ f: 7.23 })).toBe('{"f":7.23}'); | ||
expect(JSON.stringify<ObjectWithFloat>({ f: 0.000001 })).toBe( | ||
'{"f":0.000001}', | ||
); | ||
expect(JSON.stringify<ObjectWithFloat>({ f: 0.000001 })).toBe('{"f":0.000001}'); | ||
expect(JSON.stringify<ObjectWithFloat>({ f: 1e-7 })).toBe('{"f":1e-7}'); | ||
expect(JSON.stringify<ObjectWithFloat>({ f: 1e20 })).toBe( | ||
'{"f":100000000000000000000.0}', | ||
); | ||
expect(JSON.stringify<ObjectWithFloat>({ f: 1e20 })).toBe('{"f":100000000000000000000.0}'); | ||
expect(JSON.stringify<ObjectWithFloat>({ f: 1e21 })).toBe('{"f":1e+21}'); | ||
expect(JSON.stringify<ObjWithStrangeKey<string>>({ data: "foo" })).toBe( | ||
'{"a\\\\\\t\\"\\u0002b`c":"foo"}', | ||
); | ||
expect(JSON.stringify<ObjWithStrangeKey<string>>({ data: "foo" })).toBe('{"a\\\\\\t\\"\\u0002b`c":"foo"}'); | ||
}); | ||
@@ -176,79 +134,35 @@ | ||
describe("Should deserialize integer arrays", () => { | ||
expect(JSON.stringify(JSON.parse<u32[]>("[0,100,101]"))).toBe( | ||
JSON.stringify([0, 100, 101]), | ||
); | ||
expect(JSON.stringify(JSON.parse<u32[]>("[0,100,101]"))).toBe(JSON.stringify([0, 100, 101])); | ||
expect(JSON.stringify(JSON.parse<i32[]>("[0,100,101,-100,-101]"))).toBe( | ||
JSON.stringify([0, 100, 101, -100, -101]), | ||
); | ||
expect(JSON.stringify(JSON.parse<i32[]>("[0,100,101,-100,-101]"))).toBe(JSON.stringify([0, 100, 101, -100, -101])); | ||
}); | ||
describe("Should deserialize float arrays", () => { | ||
expect( | ||
JSON.stringify( | ||
JSON.parse<f64[]>("[7.23,1000.0,1000.0,1.23456,1.23456,0.0,7.23]"), | ||
), | ||
).toBe(JSON.stringify([7.23, 1000.0, 1000.0, 1.23456, 1.23456, 0.0, 7.23])); | ||
expect(JSON.stringify(JSON.parse<f64[]>("[7.23,1000.0,1000.0,1.23456,1.23456,0.0,7.23]"))).toBe(JSON.stringify([7.23, 1000.0, 1000.0, 1.23456, 1.23456, 0.0, 7.23])); | ||
expect( | ||
JSON.stringify(JSON.parse<f64[]>("[1e+21,1e+22,1e-7,1e-8,1e-9]")), | ||
).toBe(JSON.stringify([1e21, 1e22, 1e-7, 1e-8, 1e-9])); | ||
expect(JSON.stringify(JSON.parse<f64[]>("[1e+21,1e+22,1e-7,1e-8,1e-9]"))).toBe(JSON.stringify([1e21, 1e22, 1e-7, 1e-8, 1e-9])); | ||
}); | ||
describe("Should deserialize boolean arrays", () => { | ||
expect(JSON.stringify(JSON.parse<boolean[]>("[true,false]"))).toBe( | ||
JSON.stringify([true, false]), | ||
); | ||
expect(JSON.stringify(JSON.parse<boolean[]>("[true,false]"))).toBe(JSON.stringify([true, false])); | ||
}); | ||
describe("Should deserialize string arrays", () => { | ||
expect( | ||
JSON.stringify( | ||
JSON.parse<string[]>( | ||
'["string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"]', | ||
), | ||
), | ||
).toBe(JSON.stringify(['string "with random spa\nces and \nnewlines\n\n\n'])); | ||
expect(JSON.stringify(JSON.parse<string[]>('["string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"]'))).toBe(JSON.stringify(['string "with random spa\nces and \nnewlines\n\n\n'])); | ||
}); | ||
describe("Should deserialize nested integer arrays", () => { | ||
expect( | ||
JSON.stringify(JSON.parse<i64[][]>("[[100,101],[-100,-101],[0]]")), | ||
).toBe(JSON.stringify([[100, 101], [-100, -101], [0]])); | ||
expect(JSON.stringify(JSON.parse<i64[][]>("[[100,101],[-100,-101],[0]]"))).toBe(JSON.stringify([[100, 101], [-100, -101], [0]])); | ||
}); | ||
describe("Should deserialize nested float arrays", () => { | ||
expect( | ||
JSON.stringify( | ||
JSON.parse<f64[][]>( | ||
"[[7.23],[1000.0],[1000.0],[1.23456],[1.23456],[0.0],[7.23]]", | ||
), | ||
), | ||
).toBe( | ||
JSON.stringify([ | ||
[7.23], | ||
[1000.0], | ||
[1000.0], | ||
[1.23456], | ||
[1.23456], | ||
[0.0], | ||
[7.23], | ||
]), | ||
); | ||
expect(JSON.stringify(JSON.parse<f64[][]>("[[7.23],[1000.0],[1000.0],[1.23456],[1.23456],[0.0],[7.23]]"))).toBe(JSON.stringify([[7.23], [1000.0], [1000.0], [1.23456], [1.23456], [0.0], [7.23]])); | ||
}); | ||
describe("Should deserialize nested boolean arrays", () => { | ||
expect(JSON.stringify(JSON.parse<boolean[][]>("[[true],[false]]"))).toBe( | ||
JSON.stringify([[true], [false]]), | ||
); | ||
expect(JSON.stringify(JSON.parse<boolean[][]>("[[true],[false]]"))).toBe(JSON.stringify([[true], [false]])); | ||
}); | ||
describe("Should deserialize object arrays", () => { | ||
expect( | ||
JSON.stringify( | ||
JSON.parse<Vec3[]>( | ||
'[{"x":3.4,"y":1.2,"z":8.3},{"x":3.4,"y":-2.1,"z":9.3}]', | ||
), | ||
), | ||
).toBe( | ||
expect(JSON.stringify(JSON.parse<Vec3[]>('[{"x":3.4,"y":1.2,"z":8.3},{"x":3.4,"y":-2.1,"z":9.3}]'))).toBe( | ||
JSON.stringify(<Vec3[]>[ | ||
@@ -262,13 +176,5 @@ { x: 3.4, y: 1.2, z: 8.3 }, | ||
describe("Should deserialize Objects", () => { | ||
expect(JSON.stringify(JSON.parse<Vec3>('{"x":3.4,"y":1.2,"z":8.3}'))).toBe( | ||
JSON.stringify(<Vec3>{ x: 3.4, y: 1.2, z: 8.3 }), | ||
); | ||
expect(JSON.stringify(JSON.parse<Vec3>('{"x":3.4,"y":1.2,"z":8.3}'))).toBe(JSON.stringify(<Vec3>{ x: 3.4, y: 1.2, z: 8.3 })); | ||
expect( | ||
JSON.stringify( | ||
JSON.parse<Player>( | ||
'{"firstName":"Emmet","lastName":"West","lastActive":[8,27,2022],"age":23,"pos":{"x":3.4,"y":1.2,"z":8.3},"isVerified":true}', | ||
), | ||
), | ||
).toBe( | ||
expect(JSON.stringify(JSON.parse<Player>('{"firstName":"Emmet","lastName":"West","lastActive":[8,27,2022],"age":23,"pos":{"x":3.4,"y":1.2,"z":8.3},"isVerified":true}'))).toBe( | ||
JSON.stringify(<Player>{ | ||
@@ -284,15 +190,7 @@ firstName: "Emmet", | ||
expect(JSON.stringify(JSON.parse<ObjectWithFloat>('{"f":7.23}'))).toBe( | ||
JSON.stringify(<ObjectWithFloat>{ f: 7.23 }), | ||
); | ||
expect(JSON.stringify(JSON.parse<ObjectWithFloat>('{"f":7.23}'))).toBe(JSON.stringify(<ObjectWithFloat>{ f: 7.23 })); | ||
expect(JSON.stringify(JSON.parse<ObjectWithFloat>('{"f":0.000001}'))).toBe( | ||
JSON.stringify(<ObjectWithFloat>{ f: 0.000001 }), | ||
); | ||
expect(JSON.stringify(JSON.parse<ObjectWithFloat>('{"f":0.000001}'))).toBe(JSON.stringify(<ObjectWithFloat>{ f: 0.000001 })); | ||
expect( | ||
JSON.stringify( | ||
JSON.parse<ObjWithStrangeKey<string>>('{"a\\\\\\t\\"\\u0002b`c":"foo"}'), | ||
), | ||
).toBe(JSON.stringify(<ObjWithStrangeKey<string>>{ data: "foo" })); | ||
expect(JSON.stringify(JSON.parse<ObjWithStrangeKey<string>>('{"a\\\\\\t\\"\\u0002b`c":"foo"}'))).toBe(JSON.stringify(<ObjWithStrangeKey<string>>{ data: "foo" })); | ||
}); | ||
@@ -299,0 +197,0 @@ |
import { dtoa_buffered, itoa_buffered } from "util/number"; | ||
import { OBJECT, TOTAL_OVERHEAD } from "rt/common"; | ||
// @ts-ignore | ||
@inline const MAX_LEN: usize = 65536; | ||
@@ -9,5 +10,7 @@ const STORE: usize[] = []; | ||
let POINTER = changetype<usize>(CACHE); | ||
// @ts-ignore | ||
@inline const MAX_CACHE = CACHE + MAX_LEN; | ||
export namespace bs { | ||
// @ts-ignore | ||
@inline export function write_int<T extends number>(num: T): void { | ||
@@ -17,2 +20,4 @@ POINTER += itoa_buffered(POINTER, num) << 1; | ||
} | ||
// @ts-ignore | ||
@inline export function write_int_u<T extends number>(num: T): void { | ||
@@ -22,2 +27,3 @@ POINTER += itoa_buffered(POINTER, num) << 1; | ||
// @ts-ignore | ||
@inline export function write_fl<T extends number>(num: T): void { | ||
@@ -27,2 +33,4 @@ POINTER += dtoa_buffered(POINTER, num) << 1; | ||
} | ||
// @ts-ignore | ||
@inline export function write_fl_u<T extends number>(num: T): void { | ||
@@ -32,2 +40,3 @@ POINTER += dtoa_buffered(POINTER, num) << 1; | ||
// @ts-ignore | ||
@inline export function write_b(buf: usize, bytes: usize = changetype<OBJECT>(buf - TOTAL_OVERHEAD).rtSize): void { | ||
@@ -38,2 +47,4 @@ memory.copy(POINTER, buf, bytes); | ||
} | ||
// @ts-ignore | ||
@inline export function write_b_u(buf: usize, bytes: usize = changetype<OBJECT>(buf - TOTAL_OVERHEAD).rtSize): void { | ||
@@ -44,2 +55,3 @@ memory.copy(POINTER, buf, bytes); | ||
// @ts-ignore | ||
@inline export function write_s(str: string, bytes: usize = changetype<OBJECT>(changetype<usize>(str) - TOTAL_OVERHEAD).rtSize): void { | ||
@@ -50,2 +62,4 @@ memory.copy(POINTER, changetype<usize>(str), bytes); | ||
} | ||
// @ts-ignore | ||
@inline export function write_s_u(str: string, bytes: usize = changetype<OBJECT>(changetype<usize>(str) - TOTAL_OVERHEAD).rtSize): void { | ||
@@ -56,2 +70,3 @@ memory.copy(POINTER, changetype<usize>(str), bytes); | ||
// @ts-ignore | ||
@inline export function write_s_se(str: string, start: usize, end: usize): void { | ||
@@ -63,2 +78,4 @@ const bytes = end - start; | ||
} | ||
// @ts-ignore | ||
@inline export function write_s_se_u(str: string, start: usize, end: usize): void { | ||
@@ -70,2 +87,16 @@ const bytes = end - start; | ||
// @ts-ignore | ||
@inline export function write_8(char: i32): void { | ||
store<u8>(POINTER, char); | ||
POINTER += 2; | ||
if (MAX_CACHE <= POINTER) bs.shrink(); | ||
} | ||
// @ts-ignore | ||
@inline export function write_8_u(char: i32): void { | ||
store<u8>(POINTER, char); | ||
//POINTER += 2; | ||
} | ||
// @ts-ignore | ||
@inline export function write_16(char: i32): void { | ||
@@ -76,2 +107,4 @@ store<u16>(POINTER, char); | ||
} | ||
// @ts-ignore | ||
@inline export function write_16_u(char: i32): void { | ||
@@ -82,2 +115,3 @@ store<u16>(POINTER, char); | ||
// @ts-ignore | ||
@inline export function write_32(chars: i32): void { | ||
@@ -88,2 +122,4 @@ store<u32>(POINTER, chars); | ||
} | ||
// @ts-ignore | ||
@inline export function write_32_u(chars: i32): void { | ||
@@ -94,2 +130,3 @@ store<u32>(POINTER, chars); | ||
// @ts-ignore | ||
@inline export function write_64(chars: i64): void { | ||
@@ -101,2 +138,3 @@ store<u64>(POINTER, chars); | ||
// @ts-ignore | ||
@inline export function write_64_u(chars: i64): void { | ||
@@ -107,2 +145,3 @@ store<u64>(POINTER, chars); | ||
// @ts-ignore | ||
@inline export function write_128(chars: v128): void { | ||
@@ -113,7 +152,18 @@ store<v128>(POINTER, chars); | ||
} | ||
// @ts-ignore | ||
@inline export function write_128_n(chars: v128, n: usize): void { | ||
store<v128>(POINTER, chars); | ||
POINTER += n; | ||
if (MAX_CACHE <= POINTER) bs.shrink(); | ||
} | ||
// @ts-ignore | ||
@inline export function write_128_u(chars: v128): void { | ||
store<v128>(POINTER, chars); | ||
//POINTER += 16; | ||
//if (MAX_CACHE <= POINTER) bs.shrink(); | ||
//if (MAX_CACHE <= POINTER) bs.shrink(); | ||
} | ||
// @ts-ignore | ||
@inline export function shrink(): void { | ||
@@ -130,2 +180,4 @@ const len = POINTER - CACHE; | ||
} | ||
// @ts-ignore | ||
@inline export function out<T>(): T { | ||
@@ -155,2 +207,3 @@ const len = POINTER - CACHE; | ||
// @ts-ignore | ||
@inline export function out_u<T>(): T { | ||
@@ -169,5 +222,8 @@ const len = POINTER - CACHE; | ||
// @ts-ignore | ||
@inline export function _out(out: usize): void { | ||
memory.copy(out, CACHE, POINTER - CACHE); | ||
} | ||
// @ts-ignore | ||
@inline export function reset(): void { | ||
@@ -174,0 +230,0 @@ POINTER = CACHE; |
@@ -19,29 +19,12 @@ import { itoa_buffered, dtoa_buffered } from "util/number"; | ||
const sink = new Sink(); | ||
sink.buffer = changetype<ArrayBuffer>( | ||
__new( | ||
max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1), | ||
idof<ArrayBuffer>(), | ||
), | ||
); | ||
sink.buffer = changetype<ArrayBuffer>(__new(max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1), idof<ArrayBuffer>())); | ||
return sink; | ||
} | ||
static fromString( | ||
initial: string = "", | ||
capacity: i32 = MIN_BUFFER_LEN, | ||
): Sink { | ||
static fromString(initial: string = "", capacity: i32 = MIN_BUFFER_LEN): Sink { | ||
const sink = new Sink(); | ||
const size = (<u32>initial.length) << 1; | ||
sink.buffer = changetype<ArrayBuffer>( | ||
__new( | ||
max<u32>(size, max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1)), | ||
idof<ArrayBuffer>(), | ||
), | ||
); | ||
sink.buffer = changetype<ArrayBuffer>(__new(max<u32>(size, max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1)), idof<ArrayBuffer>())); | ||
if (size) { | ||
memory.copy( | ||
changetype<usize>(sink.buffer), | ||
changetype<usize>(initial), | ||
size, | ||
); | ||
memory.copy(changetype<usize>(sink.buffer), changetype<usize>(initial), size); | ||
sink.offset += size; | ||
@@ -57,7 +40,3 @@ } | ||
if (size) { | ||
memory.copy( | ||
changetype<usize>(sink.buffer), | ||
changetype<usize>(initial), | ||
size, | ||
); | ||
memory.copy(changetype<usize>(sink.buffer), changetype<usize>(initial), size); | ||
sink.offset += size; | ||
@@ -68,20 +47,8 @@ } | ||
static fromBuffer( | ||
initial: ArrayBuffer, | ||
capacity: i32 = MIN_BUFFER_LEN, | ||
): Sink { | ||
static fromBuffer(initial: ArrayBuffer, capacity: i32 = MIN_BUFFER_LEN): Sink { | ||
const sink = new Sink(); | ||
const size = <u32>initial.byteLength; | ||
sink.buffer = changetype<ArrayBuffer>( | ||
__new( | ||
max<u32>(size, max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1)), | ||
idof<ArrayBuffer>(), | ||
), | ||
); | ||
sink.buffer = changetype<ArrayBuffer>(__new(max<u32>(size, max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1)), idof<ArrayBuffer>())); | ||
if (size) { | ||
memory.copy( | ||
changetype<usize>(sink.buffer), | ||
changetype<usize>(initial), | ||
size, | ||
); | ||
memory.copy(changetype<usize>(sink.buffer), changetype<usize>(initial), size); | ||
sink.offset = size; | ||
@@ -122,7 +89,3 @@ } | ||
memory.copy( | ||
changetype<usize>(this.buffer) + offset, | ||
changetype<usize>(src) + ((<usize>start) << 1), | ||
size, | ||
); | ||
memory.copy(changetype<usize>(this.buffer) + offset, changetype<usize>(src) + ((<usize>start) << 1), size); | ||
this.offset = offset + size; | ||
@@ -147,4 +110,3 @@ return this; | ||
let dest = changetype<usize>(this.buffer) + offset; | ||
if (size) | ||
memory.copy(dest, changetype<usize>(src) + ((<usize>start) << 1), size); | ||
if (size) memory.copy(dest, changetype<usize>(src) + ((<usize>start) << 1), size); | ||
store<u16>(dest + size, NEW_LINE_CHAR); | ||
@@ -217,8 +179,6 @@ this.offset = offset + (size + 2); | ||
this.ensureCapacity(maxCapacity); | ||
offset += | ||
itoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
offset += itoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
} else { | ||
this.ensureCapacity(32 << 1); | ||
offset += | ||
dtoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
offset += dtoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
} | ||
@@ -231,7 +191,5 @@ this.offset = offset; | ||
if (isInteger<T>()) { | ||
offset += | ||
itoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
offset += itoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
} else { | ||
offset += | ||
dtoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
offset += dtoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
} | ||
@@ -244,7 +202,5 @@ this.offset = offset; | ||
if (isInteger<T>()) { | ||
offset += | ||
itoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
offset += itoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
} else { | ||
offset += | ||
dtoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
offset += dtoa_buffered(changetype<usize>(this.buffer) + offset, value) << 1; | ||
} | ||
@@ -257,17 +213,7 @@ this.offset = offset; | ||
if (clear) this.offset = 0; | ||
this.buffer = changetype<ArrayBuffer>( | ||
__renew( | ||
changetype<usize>(this.buffer), | ||
max<u32>(this.offset, max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1)), | ||
), | ||
); | ||
this.buffer = changetype<ArrayBuffer>(__renew(changetype<usize>(this.buffer), max<u32>(this.offset, max<u32>(MIN_BUFFER_SIZE, (<u32>capacity) << 1)))); | ||
} | ||
shrink(): void { | ||
this.buffer = changetype<ArrayBuffer>( | ||
__renew( | ||
changetype<usize>(this.buffer), | ||
max<u32>(this.offset, MIN_BUFFER_SIZE), | ||
), | ||
); | ||
this.buffer = changetype<ArrayBuffer>(__renew(changetype<usize>(this.buffer), max<u32>(this.offset, MIN_BUFFER_SIZE))); | ||
} | ||
@@ -291,7 +237,5 @@ | ||
if (newSize > <u32>buffer.byteLength) { | ||
this.buffer = changetype<ArrayBuffer>( | ||
__renew(changetype<usize>(buffer), nextPowerOf2(newSize)), | ||
); | ||
this.buffer = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), nextPowerOf2(newSize))); | ||
} | ||
} | ||
} |
@@ -34,7 +34,3 @@ import { isMap } from "../custom/util"; | ||
} | ||
throw new Error( | ||
"Could not parse array of type " + | ||
nameof<T>() + | ||
"! Make sure to add the @json decorator over classes!", | ||
); | ||
throw new Error("Could not parse array of type " + nameof<T>() + "! Make sure to add the @json decorator over classes!"); | ||
} else { | ||
@@ -41,0 +37,0 @@ throw new Error("Could not parse array of type " + nameof<T>() + "!"); |
@@ -0,1 +1,2 @@ | ||
import { bs } from "../custom/bs"; | ||
import { | ||
@@ -88,2 +89,71 @@ CHAR_B, | ||
return result.toString() | ||
} | ||
} | ||
// @ts-ignore: Decorator valid here | ||
// @inline export function deserializeString_BS(data: string, start: i32 = 0, end: i32 = 0): void { | ||
// end = end || data.length - 1; | ||
// let last = start + 1; | ||
// for (let i = last; i < end; i++) { | ||
// if (unsafeCharCodeAt(data, i) !== BACK_SLASH) { | ||
// continue; | ||
// } | ||
// const char = unsafeCharCodeAt(data, ++i); | ||
// bs.write_s_se_u(data, last, i - 1); | ||
// switch (char) { | ||
// case QUOTE: { | ||
// bs.write_8(QUOTE); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case BACK_SLASH: { | ||
// bs.write_8(BACK_SLASH); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case FWD_SLASH: { | ||
// bs.write_8(FWD_SLASH); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case CHAR_B: { | ||
// bs.write_8(BACKSPACE); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case CHAR_F: { | ||
// bs.write_8(FORM_FEED); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case CHAR_N: { | ||
// bs.write_8(NEW_LINE); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case CHAR_R: { | ||
// bs.write_8(CARRIAGE_RETURN); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case CHAR_T: { | ||
// bs.write_8(TAB); | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// case CHAR_U: { | ||
// const code = u16.parse(data.slice(i + 1, i + 5), 16); | ||
// bs.w(code); | ||
// i += 4; | ||
// last = i + 1; | ||
// break; | ||
// } | ||
// default: { | ||
// throw new Error(`JSON: Cannot parse "${data}" as string. Invalid escape sequence: \\${data.charAt(i)}`); | ||
// } | ||
// } | ||
// } | ||
// if (end > last) { | ||
// result.write(data, last, end); | ||
// } | ||
// } |
@@ -6,3 +6,3 @@ /// <reference path="./index.d.ts" /> | ||
import { serializeFloat } from "./serialize/float"; | ||
import { serializeObject } from "./serialize/object"; | ||
import { serializeObject, serializeObject_Pretty } from "./serialize/object"; | ||
import { serializeDate } from "./serialize/date"; | ||
@@ -17,8 +17,15 @@ import { serializeArray } from "./serialize/array"; | ||
import { deserializeDate } from "./deserialize/date"; | ||
import { BRACKET_LEFT, NULL_WORD } from "./custom/chars"; | ||
import { NULL_WORD } from "./custom/chars"; | ||
import { deserializeInteger } from "./deserialize/integer"; | ||
import { deserializeString } from "./deserialize/string"; | ||
import { Sink } from "./custom/sink"; | ||
import { bs } from "./custom/bs"; | ||
import { getArrayDepth } from "./custom/util"; | ||
// Config | ||
class SerializeOptions { | ||
public pretty: bool = false; | ||
} | ||
const DEFAULT_SERIALIZE_OPTIONS = new SerializeOptions(); | ||
/** | ||
@@ -161,175 +168,2 @@ * Offset of the 'storage' property in the JSON.Value class. | ||
} | ||
@inline | ||
@operator("==") | ||
eq(other: this): bool { | ||
if (isNullable<T>() && changetype<usize>(this) == <usize>0) { | ||
if (changetype<usize>(other) == <usize>0) return true; | ||
} | ||
return this.value == other.value; | ||
} | ||
@inline | ||
@operator("!=") | ||
notEq(other: this): bool { | ||
if (isNullable<T>() && changetype<usize>(this) == <usize>0) { | ||
if (changetype<usize>(this) == changetype<usize>(other)) return true; | ||
} | ||
return this.value != other.value; | ||
} | ||
@inline | ||
@operator(">") | ||
gt(other: this): bool { | ||
return this._val > other._val; | ||
} | ||
@inline | ||
@operator(">=") | ||
ge(other: this): bool { | ||
return this._val >= other._val; | ||
} | ||
@inline | ||
@operator("<") | ||
lt(other: this): bool { | ||
return this._val < other._val; | ||
} | ||
@inline | ||
@operator("<=") | ||
le(other: this): bool { | ||
return this._val <= other._val; | ||
} | ||
@inline | ||
@operator(">>") | ||
shr(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val >> other._val); | ||
} | ||
@inline | ||
@operator(">>>") | ||
shr_u(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val >>> other._val); | ||
} | ||
@inline | ||
@operator("<<") | ||
shl(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val << other._val); | ||
} | ||
@inline | ||
@operator("&") | ||
and(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val & other._val); | ||
} | ||
@inline | ||
@operator("|") | ||
or(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val | other._val); | ||
} | ||
@inline | ||
@operator("^") | ||
xor(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val ^ other._val); | ||
} | ||
@inline | ||
@operator("+") | ||
add(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val + other._val); | ||
} | ||
@inline | ||
@operator("-") | ||
sub(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val - other._val); | ||
} | ||
@inline | ||
@operator("*") | ||
mul(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val * other._val); | ||
} | ||
@inline | ||
@operator("/") | ||
div(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val / other._val); | ||
} | ||
@inline | ||
@operator("**") | ||
pow(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>((this._val ** other._val) as T); | ||
} | ||
@inline | ||
@operator("%") | ||
rem(other: this): this { | ||
// @ts-ignore | ||
return instantiate<this>(this._val % other._val); | ||
} | ||
@inline | ||
@operator.prefix("!") | ||
isEmpty(): bool { | ||
return !this._val; | ||
} | ||
@inline | ||
@operator.prefix("~") | ||
not(): this { | ||
return instantiate<this>(~this._val); | ||
} | ||
@inline | ||
@operator.prefix("+") | ||
pos(): this { | ||
return instantiate<this>(+this._val); | ||
} | ||
@inline | ||
@operator.prefix("-") | ||
neg(): this { | ||
return instantiate<this>(-this._val); | ||
} | ||
@operator.prefix("++") | ||
preInc(): this { | ||
// @ts-ignore | ||
++this._val; | ||
return this; | ||
} | ||
@operator.prefix("--") | ||
preDec(): this { | ||
// @ts-ignore | ||
--this._val; | ||
return this; | ||
} | ||
@operator.postfix("++") | ||
postInc(): this { | ||
return this.clone().preInc(); | ||
} | ||
@operator.postfix("--") | ||
postDec(): this { | ||
return this.clone().preDec(); | ||
} | ||
} | ||
@@ -346,3 +180,3 @@ | ||
// @ts-ignore: Decorator | ||
export function stringify<T>(data: T): string { | ||
export function stringify<T>(data: T/*, options: SerializeOptions = DEFAULT_SERIALIZE_OPTIONS*/): string { | ||
if (isBoolean<T>()) { | ||
@@ -364,2 +198,6 @@ return serializeBool(data as bool); | ||
} else if (isDefined(data.__SERIALIZE)) { | ||
/*if (options.pretty) { | ||
// @ts-ignore | ||
return serializeObject_Pretty(changetype<nonnull<T>>(data)); | ||
}*/ | ||
// @ts-ignore | ||
@@ -410,3 +248,3 @@ return serializeObject(changetype<nonnull<T>>(data)); | ||
let type: nonnull<T> = changetype<nonnull<T>>(0); | ||
// @ts-ignore: Defined by trasnform | ||
// @ts-ignore: Defined by transform | ||
if (isDefined(type.__DESERIALIZE)) { | ||
@@ -413,0 +251,0 @@ // @ts-ignore |
@@ -6,5 +6,18 @@ /** | ||
*/ | ||
import { bs } from "../custom/bs"; | ||
// @ts-ignore: Decorator valid here | ||
@inline export function serializeBool(data: bool): string { | ||
return data ? "true" : "false"; | ||
} | ||
@inline export function serializeBool_BS(data: bool): void { | ||
if (data === true) { | ||
bs.write_64(28429475166421108); /* true */ | ||
} else { | ||
//bs.write_128_n(i16x8(102, 97, 108, 115, 101, 0, 0, 0), 10); | ||
bs.write_64(32370086184550502); /* fals */ | ||
bs.write_16(101); /* e */ | ||
} | ||
} |
@@ -8,2 +8,7 @@ interface GeneratedInterface { | ||
return changetype<nonnull<T>>(data).__SERIALIZE(); | ||
} | ||
// @ts-ignore: Decorator valid here | ||
@inline export function serializeObject_Pretty<T extends GeneratedInterface>(data: T): string { | ||
return changetype<nonnull<T>>(data).__SERIALIZE_PRETTY(); | ||
} |
@@ -12,10 +12,216 @@ import { | ||
import { bs } from "../custom/bs"; | ||
import { _intTo16, intTo16 } from "../custom/util"; | ||
import { _intTo16, intTo16, unsafeCharCodeAt } from "../custom/util"; | ||
import { Sink } from "../custom/sink"; | ||
function needsEscaping(data: string): bool { | ||
let len = data.length; | ||
// if (len < 16) { | ||
// while (len--) { | ||
// const char = load<u16>(changetype<usize>(data) + len); | ||
// if (char == 34 || char == 92 || char <= 31) { | ||
// return true; | ||
// } | ||
// } | ||
// return false; | ||
// } | ||
let running = v128.splat<i64>(0); | ||
//let i = 0; | ||
//while (i + 15 < len) { | ||
let w = v128.load(changetype<usize>(data)); | ||
running = v128.or(running, v128.eq<i16>(w, i16x8.splat(34))); | ||
running = v128.or(running, v128.eq<i16>(w, i16x8.splat(92))); | ||
let subtracted = v128.sub<i16>(w, i8x16.splat(31)); | ||
running = v128.or(running, v128.eq<i16>(subtracted, v128.splat<i64>(0))); | ||
//i += 16; | ||
//} | ||
return v128.any_true(running); | ||
} | ||
/** | ||
* A prototype SIMD implementation for string serialization which can only work in 128-byte (or 16 chars with wtf-16). | ||
* | ||
* A faster version could perhaps look like the following: | ||
*/ | ||
// @ts-ignore: Decorator | ||
@inline export function serialize_simd_v1(src: string, dst: usize): void { | ||
let src_ptr = changetype<usize>(src); | ||
let dst_ptr = changetype<usize>(dst) + 2; | ||
store<u16>(changetype<usize>(dst), 34); /* " */ | ||
const src_end = src_ptr + u32(src.length << 1); | ||
const src_end_15 = src_end - 15; | ||
while (src_ptr < src_end_15) { | ||
const currentBlock = v128.load(src_ptr); | ||
const backslash_indices = i16x8.eq(currentBlock, i16x8.splat(92)); | ||
const quote_indices = i16x8.eq(currentBlock, i16x8.splat(34)); | ||
const concat_indices = v128.or(quote_indices, backslash_indices); | ||
const escape_indices = i16x8.lt_u(currentBlock, i16x8.splat(32)); | ||
if (v128.any_true(v128.or(escape_indices, concat_indices))) { | ||
const mask = i16x8.bitmask(concat_indices); | ||
const anomalies = popcnt(mask); | ||
const start_index = (clz(mask) & ~1) + 2 // This essentially floors to the nearest even integer | ||
if (anomalies === 1) { | ||
memory.copy(dst_ptr, src_ptr, start_index >> 1); | ||
store<u16>(dst_ptr + start_index, 34); | ||
memory.copy(dst_ptr + start_index + 2, src_ptr + start_index, (32 - start_index) >> 1) | ||
} | ||
if (v128.any_true(escape_indices)) { | ||
} | ||
dst_ptr += 16; | ||
src_ptr += 16; | ||
} else { | ||
v128.store(dst_ptr, currentBlock); | ||
src_ptr += 16; | ||
dst_ptr += 16; | ||
} | ||
} | ||
} | ||
const back_slash_reg = i16x8.splat(92); // "\" | ||
const quote_reg = i16x8.splat(34); // "\"" | ||
// @ts-ignore: Decorator | ||
@inline export function serialize_simd_v2(src: string, dst: usize): void { | ||
let src_ptr = changetype<usize>(src); | ||
let dst_ptr = changetype<usize>(dst); | ||
let i = 0; | ||
const len = src.length; | ||
while (i < len) { | ||
const block = v128.load16x4_u(src_ptr); | ||
console.log("block: " + prt(block)); | ||
const backslash_mask = i16x8.eq(block, back_slash_reg); | ||
const quote_mask = i16x8.eq(block, quote_reg); | ||
const is_quote_or_backslash = v128.or(quote_mask, backslash_mask); | ||
console.log("mask: " + prt10(is_quote_or_backslash)) | ||
// store<v128>(dst_ptr, expanded); | ||
src_ptr += 8; | ||
dst_ptr += 16; | ||
i += 8; | ||
} | ||
} | ||
function prt(obj: v128): string { | ||
let out = ""; | ||
out += i16x8.extract_lane_u(obj, 0).toString() + " "; | ||
out += i16x8.extract_lane_u(obj, 1).toString() + " "; | ||
out += i16x8.extract_lane_u(obj, 2).toString() + " "; | ||
out += i16x8.extract_lane_u(obj, 3).toString() + " "; | ||
out += i16x8.extract_lane_u(obj, 4).toString() + " "; | ||
out += i16x8.extract_lane_u(obj, 5).toString() + " "; | ||
out += i16x8.extract_lane_u(obj, 6).toString() + " "; | ||
out += i16x8.extract_lane_u(obj, 7).toString(); | ||
return out; | ||
} | ||
function prt10(obj: v128): string { | ||
let out = ""; | ||
out += (i16x8.extract_lane_u(obj, 0) ? "1" : "0") + " "; | ||
out += (i16x8.extract_lane_u(obj, 1) ? "1" : "0") + " "; | ||
out += (i16x8.extract_lane_u(obj, 2) ? "1" : "0") + " "; | ||
out += (i16x8.extract_lane_u(obj, 3) ? "1" : "0") + " "; | ||
out += (i16x8.extract_lane_u(obj, 4) ? "1" : "0") + " "; | ||
out += (i16x8.extract_lane_u(obj, 5) ? "1" : "0") + " "; | ||
out += (i16x8.extract_lane_u(obj, 6) ? "1" : "0") + " "; | ||
out += i16x8.extract_lane_u(obj, 7) ? "1" : "0"; | ||
return out; | ||
} | ||
function vis(src_ptr: usize, mask: i32): void { | ||
let chars = ""; | ||
let bits = ""; | ||
for (let i = 0; i < 8; i++) { | ||
const char = load<u16>(src_ptr + (i << 1)); | ||
const bit = (mask >> i) & 1; | ||
chars += String.fromCharCode(char) + " "; | ||
bits += bit.toString() + " "; | ||
} | ||
console.log(chars); | ||
console.log(bits); | ||
} | ||
// @ts-ignore: Decorator | ||
@inline export function serializeString(data: string): string { | ||
if (!needsEscaping(data)) { | ||
return "\"" + data + "\""; | ||
} | ||
if (data.length === 0) { | ||
return "\"\""; | ||
} | ||
let result = Sink.fromString("\""); | ||
let last: i32 = 0; | ||
for (let i = 0; i < data.length; i++) { | ||
const char = unsafeCharCodeAt(<string>data, i); | ||
if (char === 34 || char === 92) { | ||
result.write(<string>data, last, i); | ||
result.writeCodePoint(92); | ||
last = i; | ||
} else if (char < 16) { | ||
result.write(<string>data, last, i); | ||
last = i + 1; | ||
switch (char) { | ||
case 8: { | ||
result.write("\\b"); | ||
break; | ||
} | ||
case 9: { | ||
result.write("\\t"); | ||
break; | ||
} | ||
case 10: { | ||
result.write("\\n"); | ||
break; | ||
} | ||
case 12: { | ||
result.write("\\f"); | ||
break; | ||
} | ||
case 13: { | ||
result.write("\\r"); | ||
break; | ||
} | ||
default: { | ||
// all chars 0-31 must be encoded as a four digit unicode escape sequence | ||
// \u0000 to \u000f handled here | ||
result.write("\\u000"); | ||
result.write(char.toString(16)); | ||
break; | ||
} | ||
} | ||
} else if (char < 32) { | ||
result.write(<string>data, last, i); | ||
last = i + 1; | ||
// all chars 0-31 must be encoded as a four digit unicode escape sequence | ||
// \u0010 to \u001f handled here | ||
result.write("\\u00"); | ||
result.write(char.toString(16)); | ||
} | ||
} | ||
result.write(<string>data, last); | ||
result.writeCodePoint(34); | ||
return result.toString(); | ||
} | ||
// @ts-ignore: Decorator valid here | ||
@inline export function serializeString(data: string): string { | ||
@inline export function serializeString_BS(data: string): void { | ||
const len = data.length << 1; | ||
if (len === 0) { | ||
bs.write_32(2228258); /* "" */ | ||
return bs.out<string>(); | ||
return; | ||
} | ||
@@ -25,2 +231,3 @@ | ||
let last: i32 = 0; | ||
@@ -83,5 +290,10 @@ for (let i = 0; i < len; i += 2) { | ||
} | ||
bs.write_s_se_u(<string>data, last, changetype<OBJECT>(changetype<usize>(data) - TOTAL_OVERHEAD).rtSize); | ||
bs.write_16(QUOTE); | ||
return bs.out<string>(); | ||
if (last === 0) { | ||
bs.write_s(data); | ||
bs.write_16(QUOTE) | ||
} else { | ||
bs.write_s_se(<string>data, last, changetype<OBJECT>(changetype<usize>(data) - TOTAL_OVERHEAD).rtSize); | ||
bs.write_16(QUOTE); | ||
} | ||
} |
@@ -1,14 +0,34 @@ | ||
// import { JSON } from "."; | ||
import { JSON } from "."; | ||
import { JSON } from "." | ||
@json | ||
class ContentBlock { | ||
@omitnull() | ||
input: JSON.Raw | null = null; | ||
class Vec3<T> { | ||
public x: i32 = 0; | ||
public y: i32 = 0; | ||
public z: T; | ||
} | ||
const foo: ContentBlock = { | ||
input: "123" | ||
@json | ||
class Base { | ||
public bam: string = "harekogkeorgke" | ||
} | ||
console.log(JSON.stringify(foo)) | ||
@json | ||
class Foo extends Base { | ||
public bar: JSON.Raw = "\"this is ok\'" | ||
public baz: i32 = 0; | ||
public pos: Vec3<Vec3<i32>> = { | ||
x: 1, | ||
y: 2, | ||
z: { | ||
x: 1, | ||
y: 2, | ||
z: 3 | ||
} | ||
} | ||
// ^ this is not okay | ||
} | ||
const serialized = JSON.stringify(new Foo()); | ||
console.log("Serialized: " + serialized); | ||
const deserialized = JSON.parse<Foo>(serialized); | ||
console.log("Deserialized: " + JSON.stringify(deserialized)); |
@@ -70,3 +70,3 @@ import { Bench } from "tinybench"; | ||
.add("Parse String", () => { | ||
data = JSON.parse("[[],[[]],[[],[[]]]]"); | ||
data = JSON.stringify('hello "world abc'); | ||
}) | ||
@@ -73,0 +73,0 @@ .todo("unimplemented .add"); |
{ | ||
"name": "json-as", | ||
"version": "0.9.21", | ||
"version": "0.9.22", | ||
"description": "The only JSON library you'll need for AssemblyScript. SIMD enabled", | ||
@@ -14,3 +14,4 @@ "types": "assembly/index.ts", | ||
"Florian Guitton", | ||
"Matt Johnson-Pint" | ||
"Matt Johnson-Pint", | ||
"Tomáš Hromada" | ||
], | ||
@@ -21,6 +22,4 @@ "license": "MIT", | ||
"pretest": "rm -rf ./build/ && ast build", | ||
"build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm", | ||
"build:bench": "asc bench/benchmark.ts -o bench/benchmark.wasm --transform ./transform --optimizeLevel 3 --shrinkLevel 0 --converge --noAssert --uncheckedBehavior always --runtime stub --enable simd", | ||
"bench:wasmtime": "wasmtime ./bench/benchmark.wasm", | ||
"bench:wasmer": "wasmer --llvm ./bench/benchmark.wasm", | ||
"bench": "astral --enable simd --runtime stub", | ||
"build:test": "rm -rf ./build/ && asc assembly/test.ts --transform ./transform -o ./build/test.wasm --enable simd --enable relaxed-simd", | ||
"build:transform": "tsc -p ./transform", | ||
@@ -34,2 +33,3 @@ "test:wasmtime": "wasmtime ./build/test.wasm", | ||
"devDependencies": { | ||
"@as-tral/cli": "^3.0.2", | ||
"@assemblyscript/wasi-shim": "^0.1.0", | ||
@@ -50,3 +50,4 @@ "@types/node": "^20.14.12", | ||
"dependencies": { | ||
"as-virtual": "^0.2.0" | ||
"as-virtual": "^0.2.0", | ||
"chalk": "^5.3.0" | ||
}, | ||
@@ -53,0 +54,0 @@ "overrides": { |
@@ -6,3 +6,3 @@ <h5 align="center"> | ||
|_____||_____||_____||_|___| |__|__||_____| | ||
v0.9.21 | ||
v0.9.22 | ||
</pre> | ||
@@ -120,3 +120,3 @@ </h5> | ||
} | ||
```` | ||
``` | ||
@@ -123,0 +123,0 @@ If you use this project in your codebase, consider dropping a [star](https://github.com/JairusSW/as-json). I would really appreciate it! |
@@ -1,74 +0,74 @@ | ||
import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, } from "assemblyscript/dist/assemblyscript.js"; | ||
import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js"; | ||
import { toString, isStdlib } from "visitor-as/dist/utils.js"; | ||
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js"; | ||
import { Transform } from "assemblyscript/dist/transform.js"; | ||
import chalk from "chalk"; | ||
const json_types = ["Array", "string", "String", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Map", "Date"]; | ||
class JSONTransform extends BaseVisitor { | ||
constructor() { | ||
super(...arguments); | ||
this.schemasList = []; | ||
this.sources = new Set(); | ||
types = json_types; | ||
schemasList = []; | ||
currentClass; | ||
sources = new Set(); | ||
appendParentFields(node, schema, members) { | ||
if (node.extendsType) { | ||
if (schema.parent?.members) { | ||
for (let i = schema.parent.members.length - 1; i >= 0; i--) { | ||
const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name); | ||
if (!replace) { | ||
members.unshift(schema.parent?.members[i].node); | ||
} | ||
} | ||
this.appendParentFields(schema.parent.node, schema, members); | ||
} | ||
} | ||
} | ||
visitMethodDeclaration() { } | ||
handleEmptyClass(node, schema, members) { | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
let SERIALIZE_PRETTY_EMPTY = '__SERIALIZE_PRETTY(): string {\n return "{}";\n}'; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); | ||
const SERIALIZE_PRETTY_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_PRETTY_EMPTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) | ||
node.members.push(SERIALIZE_PRETTY_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
} | ||
filterMembers(members) { | ||
return members.filter((v) => v instanceof FieldDeclaration && !v.decorators?.find((v) => v.name.text == "omit")); | ||
} | ||
visitClassDeclaration(node) { | ||
if (!node.decorators?.length) | ||
return; | ||
let found = false; | ||
for (const decorator of node.decorators) { | ||
const name = decorator.name.text; | ||
if (name === "json" || name === "serializable") { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (!found) | ||
if (!node.decorators.find((v) => v.name.text == "json" || v.name.text == "serializable")) | ||
return; | ||
this.types = json_types; | ||
const schema = new SchemaData(); | ||
schema.node = node; | ||
schema.name = node.name.text; | ||
const members = [ | ||
...node.members.filter((v) => v.kind === 54 /* NodeKind.FieldDeclaration */), | ||
]; | ||
if (node.extendsType) { | ||
schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text); | ||
if (schema.parent?.members) { | ||
for (let i = schema.parent.members.length - 1; i >= 0; i--) { | ||
const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name); | ||
if (!replace) { | ||
members.unshift(schema.parent?.members[i].node); | ||
} | ||
} | ||
} | ||
} | ||
const _members = [...node.members]; | ||
this.appendParentFields(node, schema, _members); | ||
const members = this.filterMembers(_members); | ||
if (!members.length) { | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
//let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}"; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
//console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
this.schemasList.push(schema); | ||
this.handleEmptyClass(node, schema, members); | ||
} | ||
for (const member of members) { | ||
const name = member.name; | ||
if (!(member instanceof FieldDeclaration)) | ||
continue; | ||
if (!member.type) { | ||
throw new Error("Fields must be strongly typed! Found " + | ||
toString(member) + | ||
" at " + | ||
node.range.source.normalizedPath); | ||
throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath); | ||
} | ||
@@ -103,4 +103,3 @@ const type = toString(member.type); | ||
if (!args.length) | ||
throw new Error("Expected 1 argument but got zero at @alias in " + | ||
node.range.source.normalizedPath); | ||
throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath); | ||
mem.alias = args[0]; | ||
@@ -116,4 +115,3 @@ mem.flags.set(PropertyFlags.Alias, args); | ||
if (!decorator.args?.length) | ||
throw new Error("Expected 1 argument but got zero at @omitif in " + | ||
node.range.source.normalizedPath); | ||
throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath); | ||
mem.flags.set(PropertyFlags.OmitIf, args); | ||
@@ -129,18 +127,6 @@ break; | ||
} | ||
mem.generate(); | ||
if (!mem.flags.get(PropertyFlags.Omit)) | ||
mem.generate(); | ||
if (this.schemasList.find((v) => v.name == type)) { | ||
mem.initialize = | ||
"this." + | ||
name.text + | ||
" = changetype<nonnull<" + | ||
mem.type + | ||
">>(__new(offsetof<nonnull<" + | ||
mem.type + | ||
">>(), idof<nonnull<" + | ||
mem.type + | ||
">>()));\n changetype<nonnull<" + | ||
mem.type + | ||
">>(this." + | ||
name.text + | ||
").__INITIALIZE()"; | ||
mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()"; | ||
} | ||
@@ -157,4 +143,3 @@ else if (mem.value) { | ||
else if (type === "Array") { | ||
mem.initialize = | ||
"this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
} | ||
@@ -167,10 +152,3 @@ else if (type === "bool" || type === "boolean") { | ||
} | ||
else if (type === "u8" || | ||
type === "u16" || | ||
type === "u32" || | ||
type === "u64" || | ||
type === "i8" || | ||
type === "i16" || | ||
type === "i32" || | ||
type === "i64") { | ||
else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") { | ||
mem.initialize = "this." + name.text + " = 0"; | ||
@@ -190,11 +168,10 @@ } | ||
return; | ||
found = false; | ||
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || | ||
schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { | ||
let found = false; | ||
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { | ||
SERIALIZE_RAW += schema.members[0]?.serialize; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty; | ||
} | ||
else { | ||
SERIALIZE_RAW += schema.members[0]?.serialize + ","; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n"; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n"; | ||
found = true; | ||
@@ -208,10 +185,11 @@ } | ||
INITIALIZE += " " + member.initialize + ";\n"; | ||
if (member.flags.has(PropertyFlags.OmitNull) || | ||
member.flags.has(PropertyFlags.OmitIf)) { | ||
if (member.flags.has(PropertyFlags.Omit)) | ||
continue; | ||
if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) { | ||
SERIALIZE_RAW += member.serialize; | ||
SERIALIZE_PRETTY += member.serialize; | ||
SERIALIZE_PRETTY += member.serialize_pretty; | ||
} | ||
else { | ||
SERIALIZE_RAW += member.serialize + ","; | ||
SERIALIZE_PRETTY += indent + member.serialize + ",\\n"; | ||
SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n"; | ||
found = true; | ||
@@ -221,6 +199,4 @@ } | ||
if (found) { | ||
SERIALIZE_RAW += | ||
"`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += | ||
"`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
} | ||
@@ -254,9 +230,7 @@ else { | ||
if (first) { | ||
DESERIALIZE += | ||
" if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} | ||
else { | ||
DESERIALIZE += | ||
"else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
@@ -266,9 +240,7 @@ } | ||
if (first) { | ||
DESERIALIZE += | ||
" if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} | ||
else { | ||
DESERIALIZE += | ||
"else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
@@ -278,9 +250,7 @@ } | ||
if (first) { | ||
DESERIALIZE += | ||
" if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
first = false; | ||
} | ||
else { | ||
DESERIALIZE += | ||
"else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
} | ||
@@ -315,5 +285,3 @@ } | ||
else { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
`else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -327,5 +295,3 @@ } | ||
else { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -338,10 +304,6 @@ } | ||
else if (_name.length == 4) { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
} | ||
else { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
} | ||
@@ -354,3 +316,3 @@ DESERIALIZE += " } "; | ||
console.log(SERIALIZE_RAW); | ||
//console.log(SERIALIZE_PRETTY); | ||
console.log(SERIALIZE_PRETTY); | ||
console.log(INITIALIZE); | ||
@@ -360,3 +322,3 @@ console.log(DESERIALIZE); | ||
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node); | ||
@@ -366,2 +328,4 @@ const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node); | ||
node.members.push(SERIALIZE_RAW_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) | ||
node.members.push(SERIALIZE_PRETTY_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
@@ -392,11 +356,9 @@ node.members.push(INITIALIZE_METHOD); | ||
const b = _b.internalPath; | ||
if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} | ||
if (a[0] === "~" && b[0] !== "~") { | ||
return -1; | ||
} | ||
else if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} | ||
else { | ||
return 0; | ||
} | ||
return 0; | ||
}); | ||
@@ -413,6 +375,6 @@ // Loop over every source | ||
for (const schema of schemas) { | ||
if (schema.parent) { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
if (!parent) | ||
throw new Error(`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`); | ||
checkInheritance(schema, schemas); | ||
const invalidType = checkTypeCorrectness(schema, schemas); | ||
if (invalidType) { | ||
logError(`Type ${invalidType.type} implemented in property ${invalidType.path} is not a JSON-compatible type!\nEither decorate it with @omit or fix it!`); | ||
} | ||
@@ -422,2 +384,58 @@ } | ||
} | ||
function checkInheritance(schema, schemas) { | ||
if (!schema.parent && schema.node.extendsType) { | ||
if (schemas.find(v => v.node.name.text === schema.node.extendsType?.name.identifier.text)) | ||
return; | ||
const extending = toString(schema.node.extendsType); | ||
logError(`Schema ${schema.name} extends ${extending}, but ${extending} does not include the @json decorator!`); | ||
} | ||
} | ||
function checkTypeCorrectness(schema, schemas) { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
const generic_types = [...(schema?.node.typeParameters?.map((v) => v.name.text) || []), ...(parent?.node.typeParameters?.map((v) => v.name.text) || [])]; | ||
const member_types = [...(schema.members.map((v) => v.node.type.name.identifier.text) || [])]; | ||
const scopeTypes = new Set([...json_types, ...generic_types, ...member_types]); | ||
for (const typ of member_types) { | ||
if (typ === "JSON") | ||
continue; // JSON.Raw, JSON.Box, JSON.Any, ect... | ||
if (json_types.includes(typ)) | ||
continue; | ||
if (generic_types.includes(typ)) | ||
continue; | ||
const check = schemas.find((v) => v.name == typ); | ||
if (!check) | ||
logError(`Type ${typ} is not a JSON compatible type or does not include the @json flag!`); | ||
} | ||
for (const member of schema.members) { | ||
const invalidType = checkType(schema, schemas, member.node.type, member, scopeTypes, schema.name); | ||
if (invalidType) | ||
logError(`Type ${invalidType.type} in ${invalidType.path} does not implement a JSON compatible type!\n${chalk.dim(` at ${member.node.range.source.normalizedPath.replace("~lib/", "./node_modules/")}`)}`); | ||
} | ||
return null; | ||
} | ||
function checkType(schema, schemas, typ, member, scopeTypes, path) { | ||
path += "." + member.name; | ||
if (schemas.find(v => v.node.name.text === typ.name.identifier.text)) | ||
scopeTypes.add(typ.name.identifier.text); | ||
if (!scopeTypes.has(typ.name.identifier.text)) | ||
return { type: toString(typ), path }; | ||
if (typ.isNullable && isPrimitive(typ)) | ||
return { type: toString(typ), path }; | ||
if (typ.typeArguments?.length && typ.typeArguments?.length > 0) { | ||
for (const ty of typ.typeArguments.filter((v) => v instanceof NamedTypeNode)) { | ||
const check = checkType(schema, schemas, ty, member, scopeTypes, path); | ||
if (check) | ||
return { type: toString(typ), path }; | ||
} | ||
} | ||
else { | ||
if (scopeTypes.has(typ.name.identifier.text)) | ||
return null; | ||
} | ||
return null; | ||
} | ||
function logError(message) { | ||
console.log("\n" + chalk.bold.bgRed(" Error ") + chalk.dim(":") + " " + message + "\n"); | ||
process.exit(1); | ||
} | ||
var PropertyFlags; | ||
@@ -433,14 +451,14 @@ (function (PropertyFlags) { | ||
class Property { | ||
constructor() { | ||
this.name = ""; | ||
this.alias = null; | ||
this.type = ""; | ||
this.value = null; | ||
this.flags = new Map(); | ||
this.serialize = null; | ||
this.deserialize = null; | ||
this.initialize = null; | ||
this.right_s = ""; | ||
this.right_d = ""; | ||
} | ||
name = ""; | ||
alias = null; | ||
type = ""; | ||
value = null; | ||
flags = new Map(); | ||
serialize = null; | ||
serialize_pretty = null; | ||
deserialize = null; | ||
initialize = null; | ||
node; | ||
right_s = ""; | ||
right_d = ""; | ||
generate() { | ||
@@ -454,3 +472,3 @@ const name = this.name; | ||
if (this.flags.has(PropertyFlags.Null)) { | ||
this.right_s = "(this." + name + " || \"null\")"; | ||
this.right_s = "(this." + name + ' || "null")'; | ||
this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)"; | ||
@@ -465,4 +483,3 @@ } | ||
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")"; | ||
this.right_d = | ||
"__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
} | ||
@@ -473,22 +490,9 @@ if (this.flags.has(PropertyFlags.OmitIf)) { | ||
throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition"); | ||
this.serialize = | ||
"${" + | ||
condition + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
} | ||
else if (this.flags.has(PropertyFlags.OmitNull)) { | ||
this.serialize = | ||
"${changetype<usize>(this." + | ||
name + | ||
") == <usize>0" + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
@@ -498,2 +502,3 @@ } | ||
this.serialize = escapedName + ":${" + this.right_s + "}"; | ||
this.serialize_pretty = escapedName + ": ${" + this.right_s + "}"; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
@@ -504,7 +509,6 @@ } | ||
class SchemaData { | ||
constructor() { | ||
this.name = ""; | ||
this.members = []; | ||
this.parent = null; | ||
} | ||
name = ""; | ||
members = []; | ||
parent = null; | ||
node; | ||
} | ||
@@ -522,6 +526,3 @@ function charCodeAt32(data, offset) { | ||
const fourthCharCode = BigInt(data.charCodeAt(offset + 3)); | ||
const u64Value = (fourthCharCode << 48n) | | ||
(thirdCharCode << 32n) | | ||
(secondCharCode << 16n) | | ||
firstCharCode; | ||
const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode; | ||
return u64Value; | ||
@@ -571,1 +572,5 @@ } | ||
} | ||
function isPrimitive(type) { | ||
const primitives = new Set(["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean"]); | ||
return primitives.has(type.name.identifier.text); | ||
} |
{ | ||
"name": "@json-as/transform", | ||
"version": "0.9.21", | ||
"version": "0.9.22", | ||
"description": "The only JSON library you'll need for AssemblyScript. SIMD enabled", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
@@ -1,17 +0,2 @@ | ||
import { | ||
ClassDeclaration, | ||
FieldDeclaration, | ||
IdentifierExpression, | ||
Parser, | ||
Source, | ||
NodeKind, | ||
Expression, | ||
CommonFlags, | ||
StringLiteralExpression, | ||
IntegerLiteralExpression, | ||
FloatLiteralExpression, | ||
NullExpression, | ||
TrueExpression, | ||
FalseExpression, | ||
} from "assemblyscript/dist/assemblyscript.js"; | ||
import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, Expression, CommonFlags, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, DeclarationStatement, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js"; | ||
@@ -21,4 +6,8 @@ import { toString, isStdlib } from "visitor-as/dist/utils.js"; | ||
import { Transform } from "assemblyscript/dist/transform.js"; | ||
import chalk from "chalk"; | ||
const json_types = ["Array", "string", "String", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Map", "Date"]; | ||
class JSONTransform extends BaseVisitor { | ||
public types = json_types; | ||
public schemasList: SchemaData[] = []; | ||
@@ -28,34 +17,7 @@ public currentClass!: SchemaData; | ||
visitMethodDeclaration(): void { } | ||
visitClassDeclaration(node: ClassDeclaration): void { | ||
if (!node.decorators?.length) return; | ||
let found = false; | ||
for (const decorator of node.decorators) { | ||
const name = (<IdentifierExpression>decorator.name).text; | ||
if (name === "json" || name === "serializable") { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (!found) return; | ||
const schema = new SchemaData(); | ||
schema.node = node; | ||
schema.name = node.name.text; | ||
const members = [ | ||
...node.members.filter((v) => v.kind === NodeKind.FieldDeclaration), | ||
]; | ||
appendParentFields(node: ClassDeclaration, schema: SchemaData, members: DeclarationStatement[]): void { | ||
if (node.extendsType) { | ||
schema.parent = this.schemasList.find( | ||
(v) => v.name == node.extendsType?.name.identifier.text, | ||
) as SchemaData | null; | ||
if (schema.parent?.members) { | ||
for (let i = schema.parent.members.length - 1; i >= 0; i--) { | ||
const replace = schema.members.find( | ||
(v) => v.name == schema.parent?.members[i]?.name, | ||
); | ||
const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name); | ||
if (!replace) { | ||
@@ -65,56 +27,64 @@ members.unshift(schema.parent?.members[i]!.node); | ||
} | ||
this.appendParentFields(schema.parent.node, schema, members); | ||
} | ||
} | ||
} | ||
if (!members.length) { | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
//let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}"; | ||
handleEmptyClass(node: ClassDeclaration, schema: SchemaData, members: DeclarationStatement[]): void { | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
let SERIALIZE_PRETTY_EMPTY = '__SERIALIZE_PRETTY(): string {\n return "{}";\n}'; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let DESERIALIZE_EMPTY = | ||
"__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
//console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember( | ||
SERIALIZE_RAW_EMPTY, | ||
node, | ||
); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember( | ||
INITIALIZE_EMPTY, | ||
node, | ||
); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember( | ||
DESERIALIZE_EMPTY, | ||
node, | ||
); | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); | ||
const SERIALIZE_PRETTY_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_PRETTY_EMPTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) node.members.push(SERIALIZE_PRETTY_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
} | ||
filterMembers(members: DeclarationStatement[]): FieldDeclaration[] { | ||
return members.filter((v) => v instanceof FieldDeclaration && !v.decorators?.find((v) => (<IdentifierExpression>v.name).text == "omit")) as FieldDeclaration[]; | ||
} | ||
visitClassDeclaration(node: ClassDeclaration): void { | ||
if (!node.decorators?.length) return; | ||
if (!node.decorators.find((v) => (<IdentifierExpression>v.name).text == "json" || (<IdentifierExpression>v.name).text == "serializable")) return; | ||
this.types = json_types; | ||
this.schemasList.push(schema); | ||
const schema = new SchemaData(); | ||
schema.node = node; | ||
schema.name = node.name.text; | ||
if (node.extendsType) { | ||
schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text) as SchemaData | null; | ||
} | ||
const _members = [...node.members]; | ||
this.appendParentFields(node, schema, _members); | ||
const members = this.filterMembers(_members); | ||
if (!members.length) { | ||
this.handleEmptyClass(node, schema, members); | ||
} | ||
for (const member of members) { | ||
const name = member.name; | ||
if (!(member instanceof FieldDeclaration)) continue; | ||
if (!member.type) { | ||
throw new Error( | ||
"Fields must be strongly typed! Found " + | ||
toString(member) + | ||
" at " + | ||
node.range.source.normalizedPath, | ||
); | ||
throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath); | ||
} | ||
const type = toString(member.type!); | ||
@@ -150,7 +120,3 @@ if (type.startsWith("(") && type.includes("=>")) continue; | ||
case "alias": { | ||
if (!args.length) | ||
throw new Error( | ||
"Expected 1 argument but got zero at @alias in " + | ||
node.range.source.normalizedPath, | ||
); | ||
if (!args.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath); | ||
mem.alias = args[0]!; | ||
@@ -165,7 +131,3 @@ mem.flags.set(PropertyFlags.Alias, args); | ||
case "omitif": { | ||
if (!decorator.args?.length) | ||
throw new Error( | ||
"Expected 1 argument but got zero at @omitif in " + | ||
node.range.source.normalizedPath, | ||
); | ||
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath); | ||
mem.flags.set(PropertyFlags.OmitIf, args); | ||
@@ -182,19 +144,6 @@ break; | ||
mem.generate(); | ||
if (!mem.flags.get(PropertyFlags.Omit)) mem.generate(); | ||
if (this.schemasList.find((v) => v.name == type)) { | ||
mem.initialize = | ||
"this." + | ||
name.text + | ||
" = changetype<nonnull<" + | ||
mem.type + | ||
">>(__new(offsetof<nonnull<" + | ||
mem.type + | ||
">>(), idof<nonnull<" + | ||
mem.type + | ||
">>()));\n changetype<nonnull<" + | ||
mem.type + | ||
">>(this." + | ||
name.text + | ||
").__INITIALIZE()"; | ||
mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()"; | ||
} else if (mem.value) { | ||
@@ -207,4 +156,3 @@ mem.initialize = "this." + name.text + " = " + mem.value; | ||
} else if (type === "Array") { | ||
mem.initialize = | ||
"this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
} else if (type === "bool" || type === "boolean") { | ||
@@ -214,12 +162,3 @@ mem.initialize = "this." + name.text + " = false"; | ||
mem.initialize = "this." + name.text + ' = ""'; | ||
} else if ( | ||
type === "u8" || | ||
type === "u16" || | ||
type === "u32" || | ||
type === "u64" || | ||
type === "i8" || | ||
type === "i16" || | ||
type === "i32" || | ||
type === "i64" | ||
) { | ||
} else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") { | ||
mem.initialize = "this." + name.text + " = 0"; | ||
@@ -238,4 +177,3 @@ } else if (type === "f32" || type === "f64") { | ||
let DESERIALIZE = | ||
"__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n"; | ||
let DESERIALIZE = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n"; | ||
let indent = " "; | ||
@@ -245,18 +183,14 @@ | ||
found = false; | ||
let found = false; | ||
if ( | ||
schema.members[0]?.flags.has(PropertyFlags.OmitNull) || | ||
schema.members[0]?.flags.has(PropertyFlags.OmitIf) | ||
) { | ||
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { | ||
SERIALIZE_RAW += schema.members[0]?.serialize; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty; | ||
} else { | ||
SERIALIZE_RAW += schema.members[0]?.serialize + ","; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n"; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n"; | ||
found = true; | ||
} | ||
if (schema.members[0]?.initialize) | ||
INITIALIZE += " " + schema.members[0]?.initialize + ";\n"; | ||
if (schema.members[0]?.initialize) INITIALIZE += " " + schema.members[0]?.initialize + ";\n"; | ||
@@ -266,11 +200,9 @@ for (let i = 1; i < schema.members.length; i++) { | ||
if (member.initialize) INITIALIZE += " " + member.initialize + ";\n"; | ||
if ( | ||
member.flags.has(PropertyFlags.OmitNull) || | ||
member.flags.has(PropertyFlags.OmitIf) | ||
) { | ||
if (member.flags.has(PropertyFlags.Omit)) continue; | ||
if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) { | ||
SERIALIZE_RAW += member.serialize; | ||
SERIALIZE_PRETTY += member.serialize; | ||
SERIALIZE_PRETTY += member.serialize_pretty; | ||
} else { | ||
SERIALIZE_RAW += member.serialize + ","; | ||
SERIALIZE_PRETTY += indent + member.serialize + ",\\n"; | ||
SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n"; | ||
found = true; | ||
@@ -281,6 +213,4 @@ } | ||
if (found) { | ||
SERIALIZE_RAW += | ||
"`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += | ||
"`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
} else { | ||
@@ -294,5 +224,3 @@ SERIALIZE_RAW += "}`;\n return out;\n}"; | ||
const sortedMembers: Property[][] = []; | ||
const _sorted = schema.members.sort( | ||
(a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length), | ||
); | ||
const _sorted = schema.members.sort((a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length)); | ||
let len = -1; | ||
@@ -318,26 +246,20 @@ let offset = -1; | ||
if (first) { | ||
DESERIALIZE += | ||
" if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} else { | ||
DESERIALIZE += | ||
"else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
} else if (_name.length === 2) { | ||
if (first) { | ||
DESERIALIZE += | ||
" if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} else { | ||
DESERIALIZE += | ||
"else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
} else if (_name.length === 4) { | ||
if (first) { | ||
DESERIALIZE += | ||
" if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
first = false; | ||
} else { | ||
DESERIALIZE += | ||
"else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
} | ||
@@ -366,5 +288,3 @@ } else { | ||
} else { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
`else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -376,5 +296,3 @@ } else { | ||
} else { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -386,9 +304,5 @@ } | ||
} else if (_name.length == 4) { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
} else { | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
} | ||
@@ -404,3 +318,3 @@ DESERIALIZE += " } "; | ||
console.log(SERIALIZE_RAW); | ||
//console.log(SERIALIZE_PRETTY); | ||
console.log(SERIALIZE_PRETTY); | ||
console.log(INITIALIZE); | ||
@@ -410,16 +324,11 @@ console.log(DESERIALIZE); | ||
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember( | ||
SERIALIZE_RAW, | ||
node, | ||
); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node); | ||
const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node); | ||
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) node.members.push(SERIALIZE_PRETTY_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD); | ||
@@ -450,9 +359,9 @@ this.schemasList.push(schema); | ||
const b = _b.internalPath; | ||
if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} | ||
if (a[0] === "~" && b[0] !== "~") { | ||
return -1; | ||
} else if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
return 0; | ||
}); | ||
@@ -470,8 +379,6 @@ | ||
for (const schema of schemas) { | ||
if (schema.parent) { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
if (!parent) | ||
throw new Error( | ||
`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`, | ||
); | ||
checkInheritance(schema, schemas); | ||
const invalidType = checkTypeCorrectness(schema, schemas); | ||
if (invalidType) { | ||
logError(`Type ${invalidType.type} implemented in property ${invalidType.path} is not a JSON-compatible type!\nEither decorate it with @omit or fix it!`); | ||
} | ||
@@ -482,2 +389,72 @@ } | ||
function checkInheritance(schema: SchemaData, schemas: SchemaData[]): void { | ||
if (!schema.parent && schema.node.extendsType) { | ||
if (schemas.find(v => v.node.name.text === schema.node.extendsType?.name.identifier.text!)) return; | ||
const extending = toString(schema.node.extendsType); | ||
logError(`Schema ${schema.name} extends ${extending}, but ${extending} does not include the @json decorator!`); | ||
} | ||
} | ||
function checkTypeCorrectness( | ||
schema: SchemaData, | ||
schemas: SchemaData[] | ||
): { | ||
type: string; | ||
path: string; | ||
} | null { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
const generic_types = [...(schema?.node.typeParameters?.map<string>((v) => v.name.text) || []), ...(parent?.node.typeParameters?.map<string>((v) => v.name.text) || [])]; | ||
const member_types = [...(schema.members.map((v) => (<NamedTypeNode>v.node.type).name.identifier.text) || [])]; | ||
const scopeTypes = new Set<string>([...json_types, ...generic_types, ...member_types]); | ||
for (const typ of member_types) { | ||
if (typ === "JSON") continue; // JSON.Raw, JSON.Box, JSON.Any, ect... | ||
if (json_types.includes(typ)) continue; | ||
if (generic_types.includes(typ)) continue; | ||
const check = schemas.find((v) => v.name == typ); | ||
if (!check) logError(`Type ${typ} is not a JSON compatible type or does not include the @json flag!`); | ||
} | ||
for (const member of schema.members) { | ||
const invalidType = checkType(schema, schemas, member.node.type as NamedTypeNode, member, scopeTypes, schema.name); | ||
if (invalidType) logError(`Type ${invalidType.type} in ${invalidType.path} does not implement a JSON compatible type!\n${chalk.dim(` at ${member.node.range.source.normalizedPath.replace("~lib/", "./node_modules/")}`)}`); | ||
} | ||
return null; | ||
} | ||
function checkType( | ||
schema: SchemaData, | ||
schemas: SchemaData[], | ||
typ: NamedTypeNode, | ||
member: Property, | ||
scopeTypes: Set<string>, | ||
path: string, | ||
): { | ||
type: string; | ||
path: string; | ||
} | null { | ||
path += "." + member.name; | ||
if (schemas.find(v => v.node.name.text === typ.name.identifier.text)) scopeTypes.add(typ.name.identifier.text); | ||
if (!scopeTypes.has(typ.name.identifier.text)) return { type: toString(typ), path }; | ||
if (typ.isNullable && isPrimitive(typ)) return { type: toString(typ), path }; | ||
if (typ.typeArguments?.length && typ.typeArguments?.length > 0) { | ||
for (const ty of typ.typeArguments.filter((v) => v instanceof NamedTypeNode)) { | ||
const check = checkType(schema, schemas, ty, member, scopeTypes, path); | ||
if (check) return { type: toString(typ), path }; | ||
} | ||
} else { | ||
if (scopeTypes.has(typ.name.identifier.text)) return null; | ||
} | ||
return null; | ||
} | ||
function logError(message: string): never { | ||
console.log("\n" + chalk.bold.bgRed(" Error ") + chalk.dim(":") + " " + message + "\n"); | ||
process.exit(1); | ||
} | ||
enum PropertyFlags { | ||
@@ -497,8 +474,6 @@ Null, | ||
public value: string | null = null; | ||
public flags: Map<PropertyFlags, string[]> = new Map< | ||
PropertyFlags, | ||
string[] | ||
>(); | ||
public flags: Map<PropertyFlags, string[]> = new Map<PropertyFlags, string[]>(); | ||
public serialize: string | null = null; | ||
public serialize_pretty: string | null = null; | ||
public deserialize: string | null = null; | ||
@@ -520,3 +495,3 @@ public initialize: string | null = null; | ||
if (this.flags.has(PropertyFlags.Null)) { | ||
this.right_s = "(this." + name + " || \"null\")"; | ||
this.right_s = "(this." + name + ' || "null")'; | ||
this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)"; | ||
@@ -529,4 +504,3 @@ } else { | ||
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")"; | ||
this.right_d = | ||
"__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
} | ||
@@ -536,28 +510,13 @@ | ||
const condition = this.flags.get(PropertyFlags.OmitIf)![0]; | ||
if (!condition) | ||
throw new Error( | ||
"Could not find condition when using decorator @omitif! Provide at least one condition", | ||
); | ||
this.serialize = | ||
"${" + | ||
condition + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
if (!condition) throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition"); | ||
this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
} else if (this.flags.has(PropertyFlags.OmitNull)) { | ||
this.serialize = | ||
"${changetype<usize>(this." + | ||
name + | ||
") == <usize>0" + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
} else { | ||
this.serialize = escapedName + ":${" + this.right_s + "}"; | ||
this.serialize_pretty = escapedName + ": ${" + this.right_s + "}"; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
@@ -581,5 +540,3 @@ } | ||
if (offset + 3 >= data.length) { | ||
throw new Error( | ||
"The string must have at least 4 characters from the specified offset.", | ||
); | ||
throw new Error("The string must have at least 4 characters from the specified offset."); | ||
} | ||
@@ -592,7 +549,3 @@ | ||
const u64Value = | ||
(fourthCharCode << 48n) | | ||
(thirdCharCode << 32n) | | ||
(secondCharCode << 16n) | | ||
firstCharCode; | ||
const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode; | ||
@@ -641,1 +594,7 @@ return u64Value; | ||
} | ||
function isPrimitive(type: NamedTypeNode): boolean { | ||
const primitives = new Set(["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean"]); | ||
return primitives.has(type.name.identifier.text); | ||
} |
{ | ||
"compilerOptions": { | ||
"target": "ES2020", | ||
"module": "ES2015", | ||
"target": "ESNext", | ||
"module": "ESNext", | ||
"downlevelIteration": true, | ||
@@ -6,0 +6,0 @@ "outDir": "./lib/", |
Sorry, the diff of this file is not supported yet
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
61
4316
2
0
189430
2
14
+ Addedchalk@^5.3.0
+ Addedchalk@5.4.1(transitive)