You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP →

json-as

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.1

@@ -8,2 +8,16 @@ import { JSON } from ".."

// @ts-ignore
@json
class Vec2 {
x: f32;
y: f32;
}
class Nullable {}
type Null = Nullable | null
describe("Ser/de Nulls", () => {
canSerde<Null>(null)
})
describe("Ser/de Numbers", () => {

@@ -86,2 +100,12 @@ it("should ser/de integers", () => {

});
});
});
describe("Ser/de Objects", () => {
it("should ser/de Vec2 Objects", () => {
canSerde<Vec2>({
x: 3.4,
y: 1.2
})
})
})

@@ -18,1 +18,2 @@ export const commaCode = ",".charCodeAt(0);

export const sCode = "s".charCodeAt(0);
export const nCode = "n".charCodeAt(0);

@@ -1,460 +0,1 @@

import { StringSink } from "as-string-sink/assembly";
import { Variant } from "as-variant/assembly";
import { isSpace } from "util/string";
import {
backSlashCode,
colonCode,
commaCode,
eCode,
fCode,
forwardSlashCode,
leftBraceCode,
leftBracketCode,
quoteCode,
rightBraceCode,
rightBracketCode,
tCode,
} from "./chars";
import { removeWhitespace, unsafeCharCodeAt } from "./util";
/**
* JSON Encoder/Decoder for AssemblyScript
*/
export class JSON {
private static parseObjectValue<T>(data: string): T {
let type!: T;
if (isString<T>()) {
// @ts-ignore
return data.replaceAll('\\"', '"');
} else if (isBoolean<T>()) {
// @ts-ignore
return parseBoolean<T>(data);
} else if (isFloat<T>() || isInteger<T>()) {
return parseNumber<T>(data);
} else if (isArrayLike<T>()) {
// @ts-ignore
return parseArray<T>(data);
// @ts-ignore
} else if (isDefined(type.__JSON_Deserialize)) {
// @ts-ignore
if (isNullable<T>()) return null;
return parseObject<T>(data);
} else {
// @ts-ignore
return null;
}
}
/**
* Stringifies valid JSON data.
* ```js
* JSON.stringify<T>(data)
* ```
* @param data T
* @returns string
*/
static stringify<T = Nullable | null>(data: T): string {
// String
if (isString<T>()) {
return '"' + (<string>data).replaceAll('"', '\\"') + '"';
}
// Boolean
else if (isBoolean<T>()) {
return data ? "true" : "false";
}
// Integers/Floats
// @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;
// @ts-ignore
return data.__JSON_Serialize();
}
// ArrayLike
else if (isArrayLike<T>()) {
let result = new StringSink("[");
// @ts-ignore
if (data.length == 0) return "[]";
// @ts-ignore
for (let i = 0; i < data.length - 1; i++) {
// @ts-ignore
result.write(JSON.stringify(unchecked(data[i])) + ",");
}
// @ts-ignore
result.write(JSON.stringify(unchecked(data[data.length - 1])));
result.write("]");
return result.toString();
}
// Null
else if (isNullable<T>() && data == null) {
return "null";
} else {
return "null";
}
}
/**
* Parses valid JSON strings into their original format.
* ```js
* JSON.parse<T>(data)
* ```
* @param data string
* @returns T
*/
static parse<T = Variant>(data: string): T {
let type!: T;
if (isString<T>()) {
// @ts-ignore
return parseString(data);
} else if (isBoolean<T>()) {
// @ts-ignore
return parseBoolean<T>(data);
} else if (isFloat<T>() || isInteger<T>()) {
return parseNumber<T>(data);
} else if (isArrayLike<T>()) {
// @ts-ignore
return parseArray<T>(data.trimStart());
// @ts-ignore
} else if (isDefined(type.__JSON_Deserialize)) {
return parseObject<T>(data.trimStart());
} else {
// @ts-ignore
return null;
}
}
}
// @ts-ignore
@inline
function parseString(data: string): string {
return data.slice(1, data.length - 1).replaceAll('\\"', '"');
}
// @ts-ignore
@inline
function parseBoolean<T extends boolean>(data: string): T {
if (data.length > 3 && data.startsWith("true")) return <T>true;
else if (data.length > 4 && data.startsWith("false")) return <T>false;
else throw new Error(`JSON: Cannot parse "${data}" as boolean`);
}
// @ts-ignore
@inline
function parseNumber<T>(data: string): T {
let type: T;
// @ts-ignore
if (type instanceof f64) return F64.parseFloat(data);
// @ts-ignore
else if (type instanceof f32) return F32.parseFloat(data);
// @ts-ignore
else if (type instanceof u64) return U64.parseInt(data);
// @ts-ignore
else if (type instanceof u32) return U32.parseInt(data);
// @ts-ignore
else if (type instanceof u8) return U8.parseInt(data);
// @ts-ignore
else if (type instanceof u16) return U16.parseInt(data);
// @ts-ignore
else if (type instanceof i64) return I64.parseInt(data);
// @ts-ignore
else if (type instanceof i32) return I32.parseInt(data);
// @ts-ignore
else if (type instanceof i16) return I16.parseInt(data);
// @ts-ignore
else if (type instanceof i8) return I8.parseInt(data);
else
throw new Error(
`JSON: Cannot parse invalid data into a number. Either "${data}" is not a valid number, or <${nameof<T>()}> is an invald number type.`
);
}
// @ts-ignore
@inline
export function parseObject<T>(data: string): T {
let schema!: T;
const result = new Map<string, string>();
let key = "";
let isKey = false;
let depth = 1;
let char = 0;
for (
let outerLoopIndex = 1;
outerLoopIndex < data.length - 1;
outerLoopIndex++
) {
char = unsafeCharCodeAt(data, outerLoopIndex);
if (char === leftBracketCode) {
for (
let arrayValueIndex = outerLoopIndex;
arrayValueIndex < data.length - 1;
arrayValueIndex++
) {
char = unsafeCharCodeAt(data, arrayValueIndex);
if (char === leftBracketCode) {
depth = depth << 1;
} else if (char === rightBracketCode) {
depth = depth >> 1;
if (depth === 1) {
++arrayValueIndex;
result.set(
key,
data.slice(outerLoopIndex, arrayValueIndex)
);
outerLoopIndex = arrayValueIndex;
isKey = false;
break;
}
}
}
} else if (char === leftBraceCode) {
for (
let objectValueIndex = outerLoopIndex;
objectValueIndex < data.length - 1;
objectValueIndex++
) {
char = unsafeCharCodeAt(data, objectValueIndex);
if (char === leftBraceCode) {
depth = depth << 1;
} else if (char === rightBraceCode) {
depth = depth >> 1;
if (depth === 1) {
++objectValueIndex;
result.set(
key,
data.slice(outerLoopIndex, objectValueIndex)
);
outerLoopIndex = objectValueIndex;
isKey = false;
break;
}
}
}
} else if (char === quoteCode) {
for (
let stringValueIndex = ++outerLoopIndex;
stringValueIndex < data.length - 1;
stringValueIndex++
) {
char = unsafeCharCodeAt(data, stringValueIndex);
if (
char === quoteCode &&
unsafeCharCodeAt(data, stringValueIndex - 1) !== backSlashCode
) {
if (isKey === false) {
key = data.slice(outerLoopIndex, stringValueIndex);
isKey = true;
} else {
result.set(
key,
data.slice(outerLoopIndex, stringValueIndex)
);
isKey = false;
}
outerLoopIndex = ++stringValueIndex;
break;
}
}
} else if (
char === tCode &&
unsafeCharCodeAt(data, ++outerLoopIndex) === "r".charCodeAt(0) &&
unsafeCharCodeAt(data, ++outerLoopIndex) === "u".charCodeAt(0) &&
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
) {
result.set(key, "true");
isKey = false;
} else if (
char === fCode &&
unsafeCharCodeAt(data, ++outerLoopIndex) === "a".charCodeAt(0) &&
unsafeCharCodeAt(data, ++outerLoopIndex) === "l".charCodeAt(0) &&
unsafeCharCodeAt(data, ++outerLoopIndex) === "s".charCodeAt(0) &&
unsafeCharCodeAt(data, ++outerLoopIndex) === eCode
) {
result.set(key, "false");
isKey = false;
} else if ((char >= 48 && char <= 57) || char === 45) {
let numberValueIndex = ++outerLoopIndex;
for (; numberValueIndex < data.length - 1; numberValueIndex++) {
char = unsafeCharCodeAt(data, numberValueIndex);
if (
char === commaCode ||
isSpace(char) ||
numberValueIndex == data.length - 2
) {
result.set(
key,
data.slice(outerLoopIndex - 1, numberValueIndex)
);
outerLoopIndex = numberValueIndex;
isKey = false;
break;
}
}
}
}
// @ts-ignore
return schema.__JSON_Deserialize(result);
}
// @ts-ignore
@inline
// @ts-ignore
export function parseArray<T extends unknown[]>(data: string): T {
// TODO: Replace with opt
let type!: valueof<T>;
if (type instanceof String) {
return <T>parseStringArray(data);
} else if (isBoolean<valueof<T>>()) {
// @ts-ignore
return parseBooleanArray<T>(data);
} else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
// @ts-ignore
return parseNumberArray<T>(data);
} else if (isArrayLike<valueof<T>>()) {
// @ts-ignore
return parseArrayArray<T>(data);
// @ts-ignore
} else if (isDefined(type.__JSON_Deserialize)) {
// @ts-ignore
return parseObjectArray<T>(data);
}
}
// @ts-ignore
@inline
export function parseStringArray(data: string): string[] {
const result: string[] = [];
let lastPos = 0;
let instr = false;
for (let i = 1; i < data.length - 1; i++) {
if (unsafeCharCodeAt(data, i) === quoteCode) {
if (instr === false) {
instr = true;
lastPos = i;
} else if (unsafeCharCodeAt(data, i - 1) !== backSlashCode) {
instr = false;
result.push(data.slice(lastPos + 1, i).replaceAll('\\"', '"'));
}
}
}
return result;
}
// @ts-ignore
@inline
export function parseBooleanArray<T extends boolean[]>(data: string): T {
const result = instantiate<T>();
let lastPos = 1;
let char = 0;
for (let i = 1; i < data.length - 1; i++) {
char = unsafeCharCodeAt(data, i);
/*// if char == "t" && i+3 == "e"
if (char === tCode && data.charCodeAt(i + 3) === eCode) {
//i += 3;
result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i+2)));
//i++;
} else if (char === fCode && data.charCodeAt(i + 4) === eCode) {
//i += 4;
result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i+3)));
//i++;
}*/
if (char === tCode || char === fCode) {
lastPos = i;
} else if (char === eCode) {
i++;
result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i)));
}
}
return result;
}
// @ts-ignore
@inline
export function parseNumberArray<T extends number[]>(data: string): T {
const result = instantiate<T>();
let lastPos = 0;
let char = 0;
let i = 1;
for (; i < data.length - 1; i++) {
char = unsafeCharCodeAt(data, i);
if (lastPos === 0 && (char >= 48 && char <= 57) || char === 45) {
lastPos = i;
} else if ((isSpace(char) || char == commaCode) && lastPos > 0) {
result.push(parseNumber<valueof<T>>(data.slice(lastPos, i)));
lastPos = 0;
}
}
for (; i > lastPos - 1; i--) {
char = unsafeCharCodeAt(data, i);
if (char !== rightBracketCode) {
result.push(parseNumber<valueof<T>>(data.slice(lastPos, i + 1)));
break;
}
}
return result;
}
// @ts-ignore
@inline
export function parseArrayArray<T extends unknown[][]>(data: string): T {
const result = instantiate<T>();
let char = 0;
let lastPos = 0;
let depth = 1;
let i = 1;
// Find start of bracket
//for (; unsafeCharCodeAt(data, i) !== leftBracketCode; i++) {}
//i++;
for (; i < data.length - 1; i++) {
char = unsafeCharCodeAt(data, i);
if (char === leftBracketCode) {
if (depth === 1) {
lastPos = i;
}
// Shifting is 6% faster than incrementing
depth = depth << 1;
} else if (char === rightBracketCode) {
depth = depth >> 1;
if (depth === 1) {
i++;
result.push(JSON.parse<valueof<T>>(data.slice(lastPos, i)));
}
}
}
return result;
}
// @ts-ignore
@inline
export function parseObjectArray<T extends unknown[][]>(data: string): T {
const result = instantiate<T>();
let char = 0;
let lastPos = 1;
let depth = 1;
let i = 1;
// Find start of bracket
//for (; unsafeCharCodeAt(data, i) !== leftBracketCode; i++) { }
//i++;
for (; i < data.length - 1; i++) {
char = unsafeCharCodeAt(data, i);
if (char === leftBraceCode) {
if (depth === 1) {
lastPos = i;
}
// Shifting is 6% faster than incrementing
depth = depth << 1;
} else if (char === rightBraceCode) {
depth = depth >> 1;
if (depth === 1) {
i++;
result.push(JSON.parse<valueof<T>>(data.slice(lastPos, i)));
}
}
}
return result;
}
class Nullable { }
export { JSON } from "./json";

@@ -5,2 +5,3 @@ import "wasi";

} from ".";
import { parseObject } from "./json";

@@ -10,6 +11,3 @@ // @ts-ignore

class Vec2 {
/**
* x > 4 && x < 100
*/
private x: f32 = 0;
x: f32;
y: f32;

@@ -25,3 +23,3 @@ }

age: i32;
pos: Vec2;
pos: Vec2 | null;
isVerified: boolean;

@@ -36,2 +34,3 @@ }

pos: {
x: 3.4,
y: 1.2,

@@ -43,13 +42,9 @@ },

const vec: Vec2 = {
y: 0.0
x: 3.4,
y: 1.2
}
const serializedPlayer = JSON.stringify<Player>(player);
console.log("Serialized Player: " + serializedPlayer);
const deserializedPlayer = JSON.parse<Player>(serializedPlayer);
console.log("Deserialized Player: " + JSON.stringify(deserializedPlayer));
const serializedVec2 = JSON.stringify<Vec2>(vec);
console.log("Serialized Vec2: " + serializedVec2);
const deserializedVec2 = JSON.parse<Vec2>(serializedVec2);
console.log("Deserialized Vec2: " + JSON.stringify(deserializedVec2));
console.log("Deserialized Player: " + JSON.stringify(deserializedPlayer))
{
"name": "json-as",
"version": "0.5.0",
"version": "0.5.1",
"description": "JSON encoder/decoder for AssemblyScript",

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

"dependencies": {
"as-string-sink": "^0.5.0",
"as-variant": "^0.4.0"
"as-string-sink": "^0.5.0"
},

@@ -35,0 +34,0 @@ "repository": {

@@ -10,2 +10,3 @@ import { ClassDecorator, registerDecorator, } from "visitor-as/dist/decorator.js";

this.decodeStmts = [];
this.checkDecodeStmts = [];
}

@@ -21,3 +22,3 @@ visitMethodDeclaration() { }

}
const type = getName(node.type);
let type = getName(node.type);
// @ts-ignore

@@ -27,2 +28,4 @@ this.encodeStmts.push(`"${name}":\${JSON.stringify<${type}>(this.${name})},`);

this.decodeStmts.push(`${name}: JSON.parseObjectValue<${type}>(values.get("${name}")),\n`);
// @ts-ignore
this.checkDecodeStmts.push(' if (!values.has("${name}")) throw new Error("Key "${name}" was not found. Cannot instantiate object.");\n');
}

@@ -34,6 +37,5 @@ visitClassDeclaration(node) {

this.currentClass = node;
const name = getName(node);
this.visit(node.members);
const serializedProp = `__JSON_Serialized: string = "";`;
let serializeFunc = ``;
const serializedProp = '__JSON_Serialized: string = "";';
let serializeFunc = "";
if (this.encodeStmts.length > 0) {

@@ -59,3 +61,4 @@ const stmt = this.encodeStmts[this.encodeStmts.length - 1];

@inline
__JSON_Deserialize(values: Map<string, string>): ${name} {
__JSON_Deserialize<T>(values: Map<string, string>): T {
${process.argv.includes("--debugJSON") ? this.checkDecodeStmts.join("else") : ""}
return {

@@ -70,3 +73,2 @@ ${

this.decodeStmts = [];
//console.log(serializeFunc, deserializeFunc)
const serializedProperty = SimpleParser.parseClassMember(serializedProp, node);

@@ -73,0 +75,0 @@ node.members.push(serializedProperty);

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

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

@@ -18,2 +18,3 @@ import {

public decodeStmts: string[] = [];
public checkDecodeStmts: string[] = [];

@@ -29,4 +30,3 @@ visitMethodDeclaration(): void {}

const type = getName(node.type);
let type = getName(node.type);
// @ts-ignore

@@ -41,2 +41,5 @@ this.encodeStmts.push(

);
// @ts-ignore
this.checkDecodeStmts.push(' if (!values.has("${name}")) throw new Error("Key "${name}" was not found. Cannot instantiate object.");\n')
}

@@ -50,9 +53,7 @@ visitClassDeclaration(node: ClassDeclaration): void {

const name = getName(node);
this.visit(node.members);
const serializedProp = `__JSON_Serialized: string = "";`;
const serializedProp = '__JSON_Serialized: string = "";';
let serializeFunc = ``;
let serializeFunc = "";

@@ -79,10 +80,10 @@ if (this.encodeStmts.length > 0) {

}
const deserializeFunc = `
@inline
__JSON_Deserialize(values: Map<string, string>): ${name} {
__JSON_Deserialize<T>(values: Map<string, string>): T {
${process.argv.includes("--debugJSON") ? this.checkDecodeStmts.join("else") : ""}
return {
${
// @ts-ignore
this.decodeStmts.join("")
// @ts-ignore
this.decodeStmts.join("")
}

@@ -94,3 +95,2 @@ }

this.decodeStmts = [];
//console.log(serializeFunc, deserializeFunc)
const serializedProperty = SimpleParser.parseClassMember(

@@ -97,0 +97,0 @@ serializedProp,