🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

json-as

Package Overview
Dependencies
Maintainers
1
Versions
194
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-as - npm Package Compare versions

Comparing version

to
0.5.32

transform/lib/types.js

6

asconfig.json

@@ -15,6 +15,4 @@ {

"./transform"
],
"bindings": "esm"
},
"extends": "./node_modules/@assemblyscript/wasi-shim/asconfig.json"
]
}
}
import { JSON } from "..";
import { backSlashCode, quoteCode } from "../src/chars";
import { atoi_fast, unsafeCharCodeAt } from "../src/util";

@@ -8,43 +10,81 @@ @json

z: i32;
/*@inline __JSON_Serialize(data: Vec3): string {
return `{"x":${data.x.toString()},"y":${data.y.toString()},"z":${data.z.toString()}}`;
}*/
@inline __JSON_Deserialize(data: string, to: Vec3): Vec3 {
let last = 1;
let char = 0;
let inStr = false;
let key: string | null = null;
let pos = 0;
for (; pos < data.length - 1; pos++) {
char = unsafeCharCodeAt(data, pos);
if (inStr === false && char === quoteCode) {
if (key != null) {
if (unsafeCharCodeAt(key, 0) == 120) {
to.x = atoi_fast<i32>(data.slice(last, pos - 1))
} else if (unsafeCharCodeAt(key, 0) == 121) {
to.y = atoi_fast<i32>(data.slice(last, pos - 1))
} else if (unsafeCharCodeAt(key, 0) == 122) {
to.z = atoi_fast<i32>(data.slice(last, pos - 1))
}
}
last = ++pos;
inStr = true;
} else if (char === quoteCode && unsafeCharCodeAt(data, pos - 1) != backSlashCode) {
inStr = false;
key = data.slice(last, pos);
last = pos += 2;
}
}
if (key != null) {
if (unsafeCharCodeAt(key, 0) == 120) {
to.x = atoi_fast<i32>(data.slice(last, pos - 1))
} else if (unsafeCharCodeAt(key, 0) == 121) {
to.y = atoi_fast<i32>(data.slice(last, pos - 1))
} else if (unsafeCharCodeAt(key, 0) == 122) {
to.z = atoi_fast<i32>(data.slice(last, pos - 1))
}
}
return to;
}
}
const vec: Vec3 = blackbox<Vec3>({
x: 0,
y: 0,
z: 0
});
const vec: Vec3 = {
x: 3,
y: 1,
z: 8
};
const vecOut = new Vec3();
const i32Max = blackbox("429496729");
/*
bench("Stringify Object (Vec3)", () => {
blackbox(JSON.stringify(vec));
});
blackbox<string>(vec.__JSON_Serialize(vec));
});*/
// TODO: Make this allocate without crashing
bench("Parse Object (Vec3)", () => {
blackbox(JSON.parse<Vec3>(blackbox('{"x":0,"y":0,"z":0}')));
});/*
blackbox<Vec3>(vec.__JSON_Deserialize('{"x":0,"y":0,"z":0}', vec));
});
bench("Stringify Array", () => {
blackbox(JSON.stringify(blackbox([1, 2, 3, 4, 5])));
bench("Stringify Number Array", () => {
blackbox(JSON.stringify<i32[]>([1, 2, 3]));
});
bench("Stringify String Array", () => {
blackbox(JSON.stringify(blackbox(["a", "b", "c", "d", "e"])));
});
/*
bench("Parse Array", () => {
blackbox(JSON.parse<i32[]>(blackbox("[1,2,3,4]")));
blackbox(JSON.parse<i32[]>(blackbox("[1,2,3]")));
});
bench("Stringify Nested Array", () => {
blackbox(
JSON.stringify<string[][]>(
blackbox([
["a", "b", "c"]
])
)
);
bench("Stringify Boolean Array", () => {
blackbox(JSON.stringify<boolean[]>([true, false, true]));
});
bench("Parse Nested Array", () => {
blackbox(JSON.parse<string[][]>(blackbox('[["a","b","c"]]')));
bench("Stringify String Array", () => {
blackbox(JSON.stringify<string[]>(["a", "b", "c"]));
});
*/
bench("Stringify String", () => {

@@ -57,3 +97,3 @@ blackbox(JSON.stringify(blackbox("Hello \"World!")));

});
/*
bench("Stringify Boolean", () => {

@@ -81,2 +121,2 @@ blackbox(JSON.stringify(blackbox(true)));

blackbox(JSON.parse<f32>(blackbox("3.14")));
});*/
});

@@ -26,3 +26,3 @@ import { u128, u128Safe, u256, u256Safe, i128, i128Safe } from "as-bignum/assembly";

} from "./chars";
import { escapeChar, isBigNum, unsafeCharCodeAt } from "./util";
import { atoi_fast, escapeChar, isBigNum, unsafeCharCodeAt } from "./util";

@@ -46,30 +46,17 @@ /**

return serializeString(data);
}
// Boolean
else if (isBoolean<T>()) {
} else if (isBoolean<T>()) {
return data ? "true" : "false";
}
// Nullable
else if (isNullable<T>() && data == null) {
} else if (isNullable<T>() && data == null) {
return "null";
}
// Integers/Floats
// @ts-ignore
else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
// @ts-ignore
} else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
// @ts-ignore
return data.toString();
}
// Class-Based serialization
// @ts-ignore
else if (isDefined(data.__JSON_Serialize)) {
// @ts-ignore
//if (isNullable<T>()) return "null";
} else if (isDefined(data.__JSON_Serialize)) {
// @ts-ignore
return data.__JSON_Serialize();
}
else if (data instanceof Date) {
} else if (data instanceof Date) {
return data.toISOString();
}
// ArrayLike
else if (isArrayLike<T>()) {
} else if (isArrayLike<T>()) {
// @ts-ignore

@@ -92,14 +79,9 @@ if (data.length == 0) {

// @ts-ignore
} else if (isBoolean<valueof<T>>()) {
// @ts-ignore
return leftBracketWord + data.join(commaWord) + rightBracketWord;
// @ts-ignore
} else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
let result = new StringSink(leftBracketWord);
// @ts-ignore
for (let i = 0; i < data.length - 1; i++) {
// @ts-ignore
result.write(JSON.stringify(unchecked(data[i])));
result.write(commaWord);
}
// @ts-ignore
result.write(JSON.stringify(unchecked(data[data.length - 1])));
result.write(rightBracketWord);
return result.toString();
return leftBracketWord + data.join(commaWord) + rightBracketWord;
} else {

@@ -170,3 +152,44 @@ let result = new StringSink(leftBracketWord);

// @ts-ignore
return data.replaceAll('\\"', '"');
let result = "";
let last = 0;
let char = 0;
for (let i = 0; i < data.length; i++) {
// \\"
if (unsafeCharCodeAt(data, i) === backSlashCode) {
char = unsafeCharCodeAt(data, ++i);
result += data.slice(last, i - 1)
if (char === 34) {
result += "\"";
last = ++i;
} else if (char === 110) {
result += "\n";
last = ++i;
// 92 98 114 116 102 117
} else if (char >= 92 && char <= 117) {
if (char === 92) {
result += "\\";
last = ++i;
} else if (char === 98) {
result += "\b";
last = ++i;
} else if (char === 102) {
result += "\f";
last = ++i;
} else if (char === 114) {
result += "\r";
last = ++i;
} else if (char === 116) {
result += "\t";
last = ++i;
} else if (char === 117 && load<u64>(changetype<usize>(data) + <usize>((i + 1) << 1)) === 27584753879220272) {
result += "\u000b";
i += 4;
last = ++i;
}
}
}
}
result += data.slice(last);
// @ts-ignore
return result;
} else if (isBoolean<T>()) {

@@ -200,5 +223,5 @@ // @ts-ignore

// @ts-ignore
@inline
// @ts-ignore
function serializeString(data: string): string {

@@ -210,3 +233,3 @@ // @ts-ignore

if (data.length === 1) {
char === unsafeCharCodeAt(data, 0);
char = unsafeCharCodeAt(data, 0);
if (char === 34) {

@@ -368,2 +391,6 @@ return "\\\"";

export function parseNumber<T>(data: string): T {
if (isInteger<T>()) {
// @ts-ignore
return atoi_fast<T>(data);
}
// @ts-ignore

@@ -375,18 +402,2 @@ const type: T = 0;

else if (type instanceof f32) return f32.parse(data);
// @ts-ignore
else if (type instanceof u64) return u64.parse(data);
// @ts-ignore
else if (type instanceof u32) return u32.parse(data);
// @ts-ignore
else if (type instanceof u8) return u8.parse(data);
// @ts-ignore
else if (type instanceof u16) return u16.parse(data);
// @ts-ignore
else if (type instanceof i64) return i64.parse(data);
// @ts-ignore
else if (type instanceof i32) return i32.parse(data);
// @ts-ignore
else if (type instanceof i16) return i16.parse(data);
// @ts-ignore
else if (type instanceof i8) return i8.parse(data);
}

@@ -393,0 +404,0 @@

import { StringSink } from "as-string-sink/assembly";
import { isSpace } from "util/string";
import { CharCode, isSpace } from "util/string";
import { backSlashCode, quoteCode } from "./chars";

@@ -81,1 +81,22 @@ import { u128, u128Safe, u256, u256Safe, i128, i128Safe, i256Safe } from "as-bignum/assembly";

}
/**
* Implementation of ATOI. Can be much much faster with SIMD.
* Its pretty fast. (173m ops (atoi_fast) vs 89 ops (parseInt))
*/
@unsafe
@inline
export function atoi_fast<T extends number>(str: string): T {
// @ts-ignore
let val: T = 0;
for (let pos = 0; pos < str.length; pos += 2) {
// @ts-ignore
val = (val << 1) + (val << 3) + (load<u16>(changetype<usize>(str) + <usize>pos) - 48);
// We use load because in this case, there is no need to have bounds-checking
}
return val;
}
/**
*
*/

@@ -0,2 +1,4 @@

import { backSlashCode, quoteCode } from "./src/chars";
import { JSON } from "./src/json";
import { atoi_fast, unsafeCharCodeAt } from "./src/util";

@@ -9,31 +11,62 @@ // @json or @serializable work here

z!: f32;
@inline
__JSON_Serialize(): string {
return `{"x":${this.x.toString()},"y":${this.y.toString()},"z":${this.z.toString()}}`;
}
@inline
__JSON_Deserialize(data: string, to: Vec3): Vec3 {
let last = 1;
let char = 0;
let inStr = false;
let key: string | null = null;
let pos = 0;
for (; pos < data.length - 1; pos++) {
char = unsafeCharCodeAt(data, pos);
if (inStr === false && char === quoteCode) {
if (key != null) {
if (key == "x") {
to.x = f32.parse(data.slice(last, pos - 1))
} else if (key == "y") {
to.y = f32.parse(data.slice(last, pos - 1))
} else if (key == "z") {
to.z = f32.parse(data.slice(last, pos - 1))
}
}
last = ++pos;
inStr = true;
} else if (char === quoteCode && unsafeCharCodeAt(data, pos - 1) != backSlashCode) {
inStr = false;
key = data.slice(last, pos);
last = pos += 2;
}
}
if (key != null) {
if (key == "x") {
to.x = f32.parse(data.slice(last, pos - 1))
} else if (key == "y") {
to.y = f32.parse(data.slice(last, pos - 1))
} else if (key == "z") {
to.z = f32.parse(data.slice(last, pos - 1))
}
}
return to;
}
}
@json
class Player {
firstName!: string;
lastName!: string;
lastActive!: i32[];
age!: i32;
pos!: Vec3 | null;
isVerified!: boolean;
const vec: Vec3 = {
x: 3.4,
y: 1.2,
z: 8.3
}
const player: Player = {
firstName: "Emmet",
lastName: "West",
lastActive: [8, 27, 2022],
age: 23,
pos: {
x: 3.4,
y: 1.2,
z: 8.3
},
isVerified: true
};
const serializedVec3 = vec.__JSON_Serialize();
console.log(serializedVec3);
const stringified = JSON.stringify<Player>(player);
console.log(stringified);
const parsedVec3 = vec.__JSON_Deserialize(serializedVec3, new Vec3());
console.log(parsedVec3.__JSON_Serialize());
const parsed = JSON.parse<Player>(stringified);
console.log(JSON.stringify(parsed));
console.log(`atoi_fast("429496729"): ${atoi_fast<i32>("429496729")}`);
console.log(`strtol("429496729"): ${i32.parse("429496729")}`);
{
"name": "json-as",
"version": "0.5.31",
"version": "0.5.32",
"description": "JSON encoder/decoder for AssemblyScript",

@@ -15,3 +15,3 @@ "types": "assembly/index.ts",

"aspect": "asp",
"bench:astral": "astral",
"bench:astral": "astral -Ospeed --noAssert --uncheckedBehavior always",
"build:test": "asc assembly/test.ts --target test --runtime stub",

@@ -27,5 +27,5 @@ "build:transform": "tsc -p ./transform",

"@as-tral/cli": "^2.0.0",
"@assemblyscript/loader": "^0.27.0",
"@assemblyscript/loader": "^0.27.1",
"@assemblyscript/wasi-shim": "^0.1.0",
"assemblyscript": "^0.27.0",
"assemblyscript": "^0.27.1",
"assemblyscript-prettier": "^1.0.7",

@@ -32,0 +32,0 @@ "prettier": "^2.8.4",

@@ -5,3 +5,3 @@ # AS-JSON

Probably the fastest JSON implementation for AssemblyScript with many more optimizations coming down the pipeline.
JSON for AssemblyScript focused on performance, low-overhead, and ease-of-use.
## Installation

@@ -22,3 +22,3 @@

Add the transform to your `asc` command
Add the transform to your `asc` command (e.g. in package.json)

@@ -29,3 +29,3 @@ ```bash

Or, add it to `asconfig.json`
Alternatively, add it to your `asconfig.json`

@@ -81,6 +81,2 @@ ```

## Notes
Performance exceeds JavaScript JSON implementation by an average of 230% but this decreases with larger data packets.
## Planned Features

@@ -108,16 +104,24 @@

**Serialize Object (Vec3):** ~11.1m ops/s
Number parsing speed has doubled over the last 5 versions due to the use of a `atoi_fast` function found in `assembly/util.ts`. This can be further optimized with SIMD.
**Deserialize Object (Vec3):** ~3.2m ops/s
String serialization has more than tripled in performance (+360%). The algorithm was rewritten for less if statements and more traps.
**Serialize Array (int[]):** ~1.4m ops/s
String deserialization was quadrupled from 3.4m ops to 14.8 ops (435%). It went from using `.replaceAll` to a specialized algorithm.
**Deserialize Array (int[]):** ~2.8m ops/s
Schema (object) parsing is being optimized on GitHub and should be at least doubled if not tripled. (Current speed of barely-optimized version is 6.9m ops) This is due to taking advantage of the types with a type map and eliminating extra checking.
**Serialize String (5):** ~4.2m ops/s
**Serialize Object (Vec3):** 6.7m ops/5s
**Deserialize String (5):** ~12m ops/s
**Deserialize Object (Vec3):** 3.8m ops/5s
**Serialize Array (int[]):** 6.6m ops/5s
**Deserialize Array (int[]):** 8.6m ops/5s
**Serialize String (5):** 5.9m ops/5s
**Deserialize String (5):** 16.3m ops/5s
## Issues
Please submit an issue to https://github.com/JairusSW/as-json/issues if you find anything wrong with this library

@@ -40,2 +40,4 @@ import { getName, toString, isStdlib } from "visitor-as/dist/utils.js";

}
this.currentClass.keys.push(name);
this.currentClass.types.push(type);
// @ts-ignore

@@ -129,4 +131,2 @@ //this.decodeStmts.push(

this.schemasList.push(this.currentClass);
//console.log(serializeFunc);
//console.log(setKeyFunc);
}

@@ -133,0 +133,0 @@ visitSource(node) {

{
"name": "@json-as/transform",
"version": "0.5.31",
"version": "0.5.32",
"description": "JSON encoder/decoder for AssemblyScript",

@@ -5,0 +5,0 @@ "main": "./lib/index.js",

@@ -47,3 +47,5 @@ import {

}
this.currentClass.keys.push(name);
this.currentClass.types.push(type);
// @ts-ignore

@@ -140,3 +142,3 @@ //this.decodeStmts.push(

`
const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);

@@ -152,5 +154,2 @@ node.members.push(serializeMethod);

this.schemasList.push(this.currentClass);
//console.log(serializeFunc);
//console.log(setKeyFunc);
}

@@ -157,0 +156,0 @@ visitSource(node: Source): void {