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

{
"targets": {
"debug": {
"binaryFile": "build/untouched.wasm",
"textFile": "build/untouched.wat",
"outFile": "build/debug.wasm",
"textFile": "build/debug.wat",
"sourceMap": true,

@@ -10,6 +10,6 @@ "debug": true

"release": {
"binaryFile": "build/optimized.wasm",
"textFile": "build/optimized.wat",
"outFile": "build/release.wasm",
"textFile": "build/release.wat",
"sourceMap": true,
"optimizeLevel": 0,
"optimizeLevel": 3,
"shrinkLevel": 0,

@@ -20,4 +20,3 @@ "converge": false,

"test": {
"binaryFile": "tests/output/test.wasm",
"textFile": "tests/output/test.wat",
"outFile": "build/test.wasm",
"sourceMap": true,

@@ -28,32 +27,8 @@ "optimizeLevel": 0,

"noAssert": false
},
"bench": {
"binaryFile": "bench/output/bench.wasm",
"textFile": "bench/output/bench.wat",
"sourceMap": true,
"optimizeLevel": 3,
"shrinkLevel": 0,
"converge": false,
"noAssert": false
},
"dynamic:bench": {
"binaryFile": "dynamic/bench/output/bench.wasm",
"textFile": "dynamic/bench/output/bench.wat",
"sourceMap": true,
"optimizeLevel": 3,
"shrinkLevel": 0,
"converge": false,
"noAssert": false
},
"dynamic:test": {
"binaryFile": "dynamic/test/output/test.wasm",
"textFile": "dynamic/test/output/test.wat",
"sourceMap": true,
"optimizeLevel": 0,
"shrinkLevel": 0,
"converge": false,
"noAssert": false
}
},
"options": {}
"options": {
"transform": "./transform",
"bindings": "esm"
}
}

@@ -1,58 +0,14 @@

import { StringSink } from 'as-string-sink'
import { DynamicObject } from './DynamicObject'
import { unknown, unknownTypes } from './unknown'
export { unknown, unknownTypes } from './unknown'
export { DynamicObject as Object } from './DynamicObject'
import { StringSink } from "as-string-sink/assembly";
import { Variant } from "as-variant/assembly";
import {
backSlashCode,
colonCode,
commaCode,
leftBraceCode,
leftBracketCode,
quoteCode,
rightBraceCode,
rightBracketCode
} from "./chars";
@global
export class Nullable { }
const quote = '"'
const lbracket = "["
const rbracket = "]"
const rcbracket = "}"
const lcbracket = "{"
const trueVal = "true"
const falseVal = "false"
const nullVal = "null"
const escapeQuote = '\\"'
const quoteCode: u16 = 34// '"'
const commaCode: u16 = 44// ","
const rbracketCode: u16 = 93// "]"
const lbracketCode: u16 = 91// "["
const rcbracketCode: u16 = 125// "}"
const lcbracketCode: u16 = 123// "{"
const colonCode: u16 = 58// ":"
const fwd_slashCode: u16 = 92// "/"
const t_charCode: u16 = 116// "t"
const f_charCode: u16 = 116// "t"
const nCode: u16 = 110// "n"
const unknownId = idof<unknown>()
const stringId = idof<string>()
const objectId = idof<DynamicObject>()
const arrayStringId = idof<string[]>()
const arrayBooleanId = idof<boolean[]>()
const arrayBoolId = idof<bool[]>()
const arrayU8Id = idof<u8[]>()
const arrayU16Id = idof<u16[]>()
const arrayU32Id = idof<u32[]>()
const arrayU64Id = idof<u64[]>()
const arrayI8Id = idof<i8[]>()
const arrayI16Id = idof<i16[]>()
const arrayI32Id = idof<i32[]>()
const arrayI64Id = idof<i64[]>()
const arrayF32Id = idof<f32[]>()
const arrayF64Id = idof<f64[]>()
const arrayUnknownId = idof<unknown[]>()
const WS1code = " ".charCodeAt(0)
const WS2code = '\u0020'.charCodeAt(0)
const WS3code = '\u000A'.charCodeAt(0)
const WS4code = '\u000D'.charCodeAt(0)
const WS5code = '\u0009'.charCodeAt(0)
const unknownTrue = unknown.wrap(true)
const unknownFalse = unknown.wrap(false)
const unknownNull = unknown.wrap(null)
const fwd_slash = "\\"
const empty_stringCode = " ".charCodeAt(0)
/**

@@ -62,2 +18,3 @@ * JSON Encoder/Decoder for AssemblyScript

export namespace JSON {
export type _Variant = Variant;
/**

@@ -68,33 +25,47 @@ * Stringifies valid JSON data.

* ```
* @param data unknown
* @param data T
* @returns string
*/
*/
export function stringify<T = Nullable | null>(data: T): string {
// String
if (isString(data)) {
return serializeString(<string>data);
}
// Boolean
else if (isBoolean(data)) {
return data ? "true" : "false";
}
// Null
else if (isNullable<T>() && data == null) {
return "null";
}
// Integers/Floats
// @ts-ignore
if (isString(data)) {
return serializeString(<string>data)
} else if (isBoolean(data)) {
return serializeBoolean(data)
else if ((isInteger<T>() || isFloat<T>()) && isFinite(data)) {
// @ts-ignore
} else if (isNullable(data) && data == null) {
return nullVal
} else if (isFloat(data) || isInteger(data)) {
return data.toString()
} else if (isArrayLike(data)) {
// @ts-ignore
return serializeArray<T>(data)
} else if (data instanceof unknown) {
return serializeUnknown(data)
} else if (data instanceof DynamicObject) {
return serializeDynamicObject(data)
return data.toString();
}
// Class-Based serialization
// @ts-ignore
if (data.__encoded.length === 0) data.__encode()
// @ts-ignore
return lcbracket + data.__encoded + rcbracket
else if (isDefined(data.__JSON_Serialize)) {
//@ts-ignore
return data.__JSON_Serialize();
}
// ArrayLike
else if (isArrayLike(data)) {
let result = new StringSink("[");
if (data.length == 0) return "[]";
for (let i = 0; i < data.length - 1; i++) {
result.write(stringify(unchecked(data[i])));
result.write(",");
}
result.write(stringify(unchecked(data[data.length - 1])));
result.write("]");
return result.toString();
} else {
return "null";
}
}
/**
* Parses valid JSON strings into their original format.
* Useful for exchanging data and cloning.
* ```js

@@ -106,676 +77,264 @@ * JSON.parse<T>(data)

*/
export function parse<T = Nullable | null>(data: string): T {
const char = data.charCodeAt(0)
let type!: T
// @ts-ignore
if (isString<T>()) return parseString(data.trim())
// @ts-ignore
else if (isBoolean<T>()) return parseBoolean(data.trimLeft())
// @ts-ignore
else if (isArrayLike<T>()) return parseArray<T>(data)
// @ts-ignore
else if (isNullable<T>() && char === nCode) return null
// @ts-ignore
else if (isFloat<T>() || isInteger<T>()) return parseNumber<T>(data.trim())
// @ts-ignore
else if (type instanceof unknown) return parseUnknown(data)
// @ts-ignore
else if (type instanceof DynamicObject) return parseDynamicObject(data)
// @ts-ignore
return parseObject<T>(data)
}
}
export function 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>()) {
return parseArray<T>(data);
// @ts-ignore
} else if (isDefined(type.__JSON_Deserialize)) {
const len: u32 = data.length - 1
let schema!: T
const result = new Map<string, string>()
let lastPos: u32 = 1
let key: string = ''
let instr: u32 = 0
let char: u32 = 0
let depth: u32 = 0
let fdepth: u32 = 0
for (let i: u32 = 1; i < len; i++) {
char = data.charCodeAt(i)
if (char === "\"".charCodeAt(0) && data.charCodeAt(i - 1) !== "/".charCodeAt(0)) instr = (instr ? 0 : 1)
else if (instr === 0) {
if (char === leftBraceCode || char === leftBracketCode) depth++
if (char === rightBraceCode || char === rightBracketCode) fdepth++
}
if (depth !== 0 && depth === fdepth) {
result.set(key, data.slice(lastPos + 1, i + 1))
// Reset the depth
depth = 0
fdepth = 0
// Set new lastPos
lastPos = i + 1
}
if (depth === 0) {
if (char === colonCode) {
key = data.slice(lastPos + 1, i - 1)
lastPos = i
}
else if (char === commaCode) {
if ((i - lastPos) > 0) result.set(key, data.slice(lastPos + 1, i))
lastPos = i + 1
}
}
}
export function serializeDynamicObject(data: DynamicObject): string {
const result = new StringSink(lcbracket)
const keys = DynamicObject.keys(data)
const values = DynamicObject.values(data)
const len: u32 = keys.length - 1
if (len === -1) return '{}'
for (let i: u32 = 0; i < len; i++) {
result.write(`"${unchecked(keys[i])}":${serializeUnknown(unchecked(values[i]))},`)
}
result.write(`"${unchecked(keys[len])}":${serializeUnknown(unchecked(values[len]))}}`)
return result.toString()
}
export function serializeUnknown(data: unknown): string {
// @ts-ignore
if (data.type === unknownTypes.null) {
return nullVal
}
// @ts-ignore
else if (data.type === unknownId) {
// @ts-ignore
return serializeUnknown(data.get<unknown>())
}
// @ts-ignore
else if (data.type === stringId) {
// @ts-ignore
return serializeString(data.get<string>())
}
// @ts-ignore
else if (data.type === unknownTypes.boolean) {
// @ts-ignore
return serializeBoolean(data.get<boolean>())
}
// @ts-ignore
else if (data.type === unknownTypes.i8) {
// @ts-ignore
return data.get<i8>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.i16) {
// @ts-ignore
return data.get<i16>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.i32) {
// @ts-ignore
return data.get<i32>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.i64) {
// @ts-ignore
return data.get<i64>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.u8) {
// @ts-ignore
return data.get<u8>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.u16) {
// @ts-ignore
return data.get<u16>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.u32) {
// @ts-ignore
return data.get<u32>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.u64) {
// @ts-ignore
return data.get<u64>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.f32) {
// @ts-ignore
return data.get<f32>().toString()
}
// @ts-ignore
else if (data.type === unknownTypes.f64) {
// @ts-ignore
return data.get<f64>().toString()
}
// @ts-ignore
else if (data.type === objectId) {
// @ts-ignore
return serializeDynamicObject(data.get<DynamicObject>())
}
// @ts-ignore
else if (data.type === arrayUnknownId) {
// @ts-ignore
return serializeUnknownArray(data.get<unknown[]>())
}
// @ts-ignore
else if (data.type === arrayBoolId) {
// @ts-ignore
return serializeBooleanArray(data.get<bool[]>())
}
// @ts-ignore
else if (data.type === arrayBooleanId) {
// @ts-ignore
return serializeBooleanArray(data.get<boolean[]>())
}
// @ts-ignore
else if (data.type === arrayF32Id) {
// @ts-ignore
return serializeNumberArray<f32[]>(data.get<f32[]>())
}
// @ts-ignore
else if (data.type === arrayF64Id) {
// @ts-ignore
return serializeNumberArray<f64[]>(data.get<f64[]>())
}
// @ts-ignore
else if (data.type === arrayU8Id) {
// @ts-ignore
return serializeNumberArray<u8[]>(data.get<u8[]>())
}
// @ts-ignore
else if (data.type === arrayU16Id) {
// @ts-ignore
return serializeNumberArray<u16[]>(data.get<u16[]>())
}
// @ts-ignore
else if (data.type === arrayU32Id) {
// @ts-ignore
return serializeNumberArray<u32[]>(data.get<u32[]>())
}
// @ts-ignore
else if (data.type === arrayU64Id) {
// @ts-ignore
return serializeNumberArray<u64[]>(data.get<u64[]>())
}
// @ts-ignore
else if (data.type === arrayI8Id) {
// @ts-ignore
return serializeNumberArray<i8[]>(data.get<i8[]>())
}
// @ts-ignore
else if (data.type === arrayI16Id) {
// @ts-ignore
return serializeNumberArray<i16[]>(data.get<i16[]>())
}
// @ts-ignore
else if (data.type === arrayI32Id) {
// @ts-ignore
return serializeNumberArray<i32[]>(data.get<i32[]>())
}
// @ts-ignore
else if (data.type === arrayI64Id) {
// @ts-ignore
return serializeNumberArray<i64[]>(data.get<i64[]>())
}
// @ts-ignore
else if (data.type === arrayStringId) {
// @ts-ignore
return serializeStringArray(data.get<string[]>())
}
// @ts-ignore
else {
return nullVal
}
}
export function serializeNumber<T>(data: T): string {
// @ts-ignore
return data.toString()
}
export function serializeString(data: string): string {
return quote + data.replaceAll(quote, escapeQuote) + quote
}
export function serializeBoolean(data: number): string {
return data ? trueVal : falseVal
}
function serializeStringArray(data: string[]): string {
const result = new StringSink(lbracket)
const len: u32 = data.length - 1
for (let i: u32 = 0; i < len; i++) {
result.write(serializeString(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeString(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
}
function serializeNumberArray<T extends Array<any>>(data: T): string {
const result = new StringSink(lbracket)
const len: u32 = data.length - 1
for (let i: u32 = 0; i < len; i++) {
result.write(serializeNumber<valueof<T>>(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeNumber<valueof<T>>(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
}
function serializeBooleanArray(data: boolean[]): string {
const result = new StringSink(lbracket)
const len: u32 = data.length - 1
for (let i: u32 = 0; i < len; i++) {
// @ts-ignore
result.write(serializeBoolean(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
// @ts-ignore
result.write(serializeBoolean(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
}
function serializeUnknownArray(data: unknown[]): string {
const result = new StringSink(lbracket)
const len: u32 = data.length - 1
for (let i: u32 = 0; i < len; i++) {
result.write(serializeUnknown(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeUnknown(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
}
function serializeDeepArray<T extends Array<any>>(data: T): string {
const result = new StringSink(lbracket)
const len: u32 = data.length - 1
for (let i: u32 = 0; i < len; i++) {
result.write(serializeArray<valueof<T>>(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeArray<valueof<T>>(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
}
function serializeObjectArray<T extends Array<any>>(data: T): string {
const result = new StringSink(lbracket)
const len: u32 = data.length - 1
let obj!: valueof<T>
for (let i: u32 = 0; i < len; i++) {
obj = unchecked(data[i])
if (obj.__encoded.length === 0) obj.__encode()
result.write(obj.__encoded)
result.writeCodePoint(commaCode)
}
obj = unchecked(data[len])
if (obj.__encoded.length === 0) obj.__encode()
result.write(obj.__encoded)
result.writeCodePoint(rbracketCode)
return result.toString()
}
function serializeDynamicObjectArray(data: DynamicObject[]): string {
const result = new StringSink(lbracket)
const len: u32 = data.length - 1
for (let i: u32 = 0; i < len; i++) {
result.write(serializeDynamicObject(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeDynamicObject(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
}
export function serializeArray<T extends Array<any>>(data: T): string {
let type!: valueof<T>
const len = data.length - 1;
if (len === -1) return lbracket + rbracket
let result = new StringSink(lbracket);
if (isString<valueof<T>>()) {
for (let i = 0; i < len; i++) {
result.write(serializeString(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeString(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
} else if (isFloat<valueof<T>>() || isInteger<valueof<T>>()) {
for (let i = 0; i < len; i++) {
result.write(serializeNumber<valueof<T>>(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeNumber<valueof<T>>(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
} else if (isBoolean<valueof<T>>()) {
for (let i = 0; i < len; i++) {
result.write(serializeBoolean(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeBoolean(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
// @ts-ignore
} else if (type instanceof unknown) {
for (let i = 0; i < len; i++) {
result.write(serializeUnknown(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeUnknown(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
} else if (isArray<valueof<T>>()) {
for (let i = 0; i < len; i++) {
result.write(serializeArray<valueof<T>>(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeArray<valueof<T>>(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
// @ts-ignore
} else if (type instanceof DynamicObject) {
for (let i = 0; i < len; i++) {
result.write(serializeDynamicObject(unchecked(data[i])))
result.writeCodePoint(commaCode)
}
result.write(serializeDynamicObject(unchecked(data[len])))
result.writeCodePoint(rbracketCode)
return result.toString()
} else {
for (let i = 0; i < len; i++) {
const elem = unchecked(data[i])
if ((len - lastPos) > 0) result.set(key, data.slice(lastPos + 1, len))
// @ts-ignore
if (elem.__encoded.length === 0) elem.__encode()
return schema.__JSON_Deserialize(result)
} else {
// @ts-ignore
return null;
}
// @ts-ignore
result.write(elem.__encoded)
result.writeCodePoint(rcbracketCode)
}
return result.toString()
}
export function parseUnknown(data: string): unknown {
const char = data.charCodeAt(0)
// @ts-ignore
if (char === quoteCode) return unknown.wrap(parseString(data))
// @ts-ignore
else if (char === t_charCode) return unknownTrue
else if (char === f_charCode) return unknownFalse
// @ts-ignore
else if (char === lbracketCode) return unknown.wrap(parseUnknownArray(data))
// @ts-ignore
else if (char === nCode) return unknownNull
// @ts-ignore
//else if (char === lcbracketCode) return parseObject<T>(data)
// @ts-ignore
return parseUnknownNumber(data)
// @ts-ignore
@inline
function serializeString(data: string): string {
return '"' + data.replaceAll('"', '\\"') + '"';
}
export function parseBoolean(data: string): boolean {
return data.charCodeAt(0) === t_charCode ? true : false
// @ts-ignore
@inline
function parseString(data: string): string {
return data.slice(1, data.length - 1).replaceAll('\\"', '"');
}
export function parseString(data: string): string {
return data.slice(1, data.length - 1).replaceAll(escapeQuote, quote)
// @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`);
}
export function parseNumber<T>(data: string): T {
let type: T
// @ts-ignore
@inline
function parseNumber<T>(data: string): T {
let type: T;
// @ts-ignore
if (type instanceof f64) return F64.parseFloat(data)
if (type instanceof f64) return F64.parseFloat(data);
// @ts-ignore
else if (type instanceof f32) return F32.parseFloat(data)
else if (type instanceof f32) return F32.parseFloat(data);
// @ts-ignore
else if (type instanceof i32) return I32.parseInt(data)
else if (type instanceof i32) return I32.parseInt(data);
// @ts-ignore
else if (type instanceof u32) return U32.parseInt(data)
else if (type instanceof u32) return U32.parseInt(data);
// @ts-ignore
else if (type instanceof u64) return U64.parseInt(data)
else if (type instanceof u8) return U8.parseInt(data);
// @ts-ignore
else if (type instanceof i64) return I64.parseInt(data)
else if (type instanceof u16) return U16.parseInt(data);
// @ts-ignore
else if (type instanceof u8) return U8.parseInt(data)
else if (type instanceof i16) return I16.parseInt(data);
// @ts-ignore
else if (type instanceof u16) return U16.parseInt(data)
// @ts-ignore
else if (type instanceof i16) return I16.parseInt(data)
// @ts-ignore
return I8.parseInt(data)
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.`
);
}
export function parseUnknownNumber(data: string): unknown {
// @ts-ignore
if (data.includes('.')) return unknown.wrap(F64.parseFloat(data))
// @ts-ignore
return unknown.wrap(I64.parseInt(data))
}
export function parseArray<T extends Array<unknown>>(data: string): T {
let type!: valueof<T>
// @ts-ignore
if (isString<valueof<T>>()) return parseStringArray(data)
// @ts-ignore
else if (isBoolean<valueof<T>>()) return parseBooleanArray(data)
// @ts-ignore
else if (isArray<valueof<T>>()) return parseArrayArray<T>(data)
// @ts-ignore
else if (type instanceof unknown) return parseUnknownArray(data)
// @ts-ignore
return parseNumberArray<valueof<T>>(data)
}
export function parseStringArray(data: string): Array<string> {
const result = new Array<string>()
if (data.length === 2) return result
let lastPos: u32 = 1
let char: u32 = 0
let instr: boolean = false
for (let i: u32 = 1; i < u32(data.length - 1); i++) {
char = data.charCodeAt(i)
// This ignores [ and ] or { and } if they are inside a string.
if (char === quoteCode && data.charCodeAt(i - 1) !== fwd_slashCode) instr = instr ? false : true
if (instr === false) {
// Handles whitespace after a comma
if (char === WS1code || char === WS2code || char === WS3code || char === WS4code || char === WS5code) lastPos++
if (char === quoteCode) {
result.push(parseString(data.slice(lastPos, i + 1)))
lastPos = i + 2
}
// @ts-ignore
@inline
export function parseNumberArray<T>(data: string): T {
const result = instantiate<T>();
if (data.length == 0) return result;
let lastPos: u32 = 1;
let i: u32 = 1;
let char: u32 = 0;
for (; i < u32(data.length - 1); i++) {
char = data.charCodeAt(i);
if (char == commaCode) {
// console.log(data.slice(lastPos, i))
// @ts-ignore
result.push(parseNumber<valueof<T>>(data.slice(lastPos, i).trim()));
lastPos = ++i;
}
}
return result
//console.log(data.slice(lastPos, data.length - 1))
// @ts-ignore
result.push(
// @ts-ignore
parseNumber<valueof<T>>(data.slice(lastPos, data.length - 1).trimStart())
);
return result;
}
export function parseBooleanArray(data: string): Array<boolean> {
const result = new Array<boolean>()
if (data.length === 2) return result
let char: u32 = 0
let instr: boolean = false
for (let i: u32 = 1; i < u32(data.length - 1); i++) {
char = data.charCodeAt(i)
if (instr === false) {
if (char === t_charCode) {
result.push(true)
i += 4
} else {
result.push(false)
i += 5
}
}
}
return result
}
export function parseNumberArray<T>(data: string): Array<T> {
const result = new Array<T>()
if (data.length === 2) return result
let lastPos: u32 = 0
let char: u32 = 0
let i: u32 = 1
// @ts-ignore
@inline
export function parseBooleanArray<T>(data: string): T {
const result = instantiate<T>();
if (data.length == 0) return result;
let lastPos: u32 = 1;
let i: u32 = 1;
let char: u32 = 0;
for (; i < u32(data.length - 1); i++) {
char = data.charCodeAt(i)
if (char === commaCode) {
//console.log('Found number: ' + data.slice(lastPos + 1, i))
result.push(parseNumber<T>(data.slice(lastPos + 1, i)))
lastPos = i
char = data.charCodeAt(i);
if (char == commaCode) {
// @ts-ignore
result.push(parseBoolean<valueof<T>>(data.slice(lastPos, i).trimStart()));
lastPos = ++i;
}
}
// console.log('Found number: ' + data.slice(lastPos + 1, i))
result.push(parseNumber<T>(data.slice(lastPos + 1, i)))
return result
// @ts-ignore
result.push(
// @ts-ignore
parseBoolean<valueof<T>>(data.slice(lastPos, data.length - 1).trimStart())
);
return result;
}
export function parseUnknownArray(data: string): Array<unknown> {
const result = new Array<unknown>()
if (data.length === 2) return result
let lastPos: i32 = 0
let char: u32 = 0
let depth: u32 = 0
let fdepth: u32 = 0
let instr: boolean = false
let i: u32 = 1
for (; i < u32(data.length - 1); i++) {
char = data.charCodeAt(i)
// This ignores [ and ] if they are inside a string.
if (char === quoteCode && data.charCodeAt(i - 1) !== fwd_slashCode) {
if (instr === true) {
instr = false
} else {
instr = true
}
// @ts-ignore
@inline
export function parseArray<T>(data: string): T {
const result = instantiate<T>();
data = data.trim();
let len: u32 = data.length - 1;
let lastPos: u32 = 1;
let i: u32 = 1;
let char: u32 = 0;
// Is struct such as Object, or Array
let isStruct: boolean = false;
let isStr: boolean = false;
//let offset: u32 = 0;
// Depth for finding matching brackets
let inDepth: u32 = 0;
let outDepth: u32 = 0;
for (; i < len; i++) {
char = data.charCodeAt(i);
if (char == quoteCode && data.charCodeAt(i - 1) != backSlashCode)
isStr = !isStr;
if (char == leftBraceCode || char == leftBracketCode) {
inDepth++;
isStruct = true;
} else if (char == rightBraceCode || char == rightBracketCode) {
outDepth++;
isStruct = true;
}
if (instr === false) {
if (char === commaCode && depth === 0 && fdepth === 0) {
//console.log('Normal chunk: ' + data.slice(lastPos + 1, i))
result.push(parseUnknown(data.slice(lastPos + 1, i).trim()))
lastPos = i
} else if (char === lbracketCode) depth++
else if (char === rbracketCode) fdepth++
else if (depth !== 0 && depth === fdepth) {
//console.log('Deep chunk: ' + data.slice(lastPos + 1, i))
result.push(unknown.wrap(parseUnknownArray(data.slice(lastPos + 1, i).trim())))
// Reset the depth
depth = 0
fdepth = 0
// Set new lastPos
lastPos = i
}
}
}
// console.log('Last chunk: ' + data.slice(lastPos + 1, data.length - 1).trim())
result.push(parseUnknown(data.slice(lastPos + 1, data.length - 1).trim()))
return result
}
export function parseArrayArray<T extends Array<unknown>>(data: string): T {
const result = instantiate<T>()
if (data.length === 2) return result
let lastPos: i32 = -1
let char: u32 = 0
let depth: u32 = 0
let fdepth: u32 = 0
let instr: u32 = 0
for (let i: u32 = 1; i < u32(data.length - 1); i++) {
char = data.charCodeAt(i)
// This ignores [ and ] if they are inside a string.
if (char === quoteCode && data.charCodeAt(i - 1) !== fwd_slashCode) instr = instr ? 0 : 1
// This gets the depth of the array.
if (instr === 0) {
if (char === lbracketCode) depth++
if (char === rbracketCode) fdepth++
// If the depth and found depth are equal, that is an array. Push it.
if (depth !== 0 && depth === fdepth) {
result.push(
if (!isStr) {
if (!isStruct) {
// This removes whitespace before and after an element
/*if (offset != 0 && isSpace(char)) {
lastPos++;
} else {
if (isSpace(char)) offset++;
}*/
// This checks to see if we are dealing with structures such as Objects and Arrays
if (char == commaCode) {
// @ts-ignore
parseArray<valueof<T>>(data.slice(lastPos + 2, i + 1))
)
// Reset the depth
depth = 0
fdepth = 0
// Set new lastPos
lastPos = i
result.push(JSON.parse<valueof<T>>(data.slice(lastPos, i).trim()));
//offset = 0;
lastPos = i + 1;
}
} else {
if (inDepth == outDepth) {
i++;
//console.log(`Struct-${data.slice(lastPos, i).trim()}-`)
lastPos = i + 1;
inDepth = 0;
outDepth = 0;
isStruct = false;
}
}
}
}
// Return the final array
return result
}
export function parseObject<T>(data: string): T {
//console.log('Data ' + data)
data = removeJSONWhitespace(data)
const len: u32 = data.length - 1
let schema: T
const result = new Map<string, string>()
let lastPos: u32 = 1
let key: string = ''
let instr: u32 = 0
let char: u32 = 0
let depth: u32 = 0
let fdepth: u32 = 0
for (let i: u32 = 1; i < len; i++) {
char = data.charCodeAt(i)
if (char === quoteCode && data.charCodeAt(i - 1) !== fwd_slashCode) instr = (instr ? 0 : 1)
else if (instr === 0) {
if (char === lcbracketCode || char === lbracketCode) depth++
if (char === rcbracketCode || char === rbracketCode) fdepth++
}
if (depth !== 0 && depth === fdepth) {
//console.log(`Deep: ${data.slice(lastPos + 1, i + 1)}`)
result.set(key, data.slice(lastPos + 1, i + 1).trim())
// Reset the depth
depth = 0
fdepth = 0
// Set new lastPos
lastPos = i + 1
}
if (depth === 0) {
if (char === colonCode) {
//console.log(`Key: ${data.slice(lastPos + 1, i - 1)}`)
key = data.slice(lastPos + 1, i - 1).trim()
lastPos = i
}
else if (char === commaCode) {
//console.log(`Value: ${data.slice(lastPos + 1, i)}`)
if ((i - lastPos) > 0) result.set(key, data.slice(lastPos + 1, i).trim())
lastPos = i + 1
}
}
/*char = data.charCodeAt(lastPos)
// Remove preceeding whitespace
while (isSpace(char)) {
lastPos++;
char = data.charCodeAt(lastPos);
}
//console.log(`Trailing: ${data.slice(lastPos + 1, len)}\n\t\sValid: ${data.slice(lastPos + 1, len).length > 0}`)
char = data.charCodeAt(--len);
while (isSpace(char)) {
len--;
char = data.charCodeAt(len);
}*/
if ((len - lastPos) > 0) result.set(key, data.slice(lastPos + 1, len).trim())
// @ts-ignore
return schema.__decode(result)
// Handle empty arrays
data = data.slice(lastPos, len).trim();
// @ts-ignore
if (data.length != 0) result.push(JSON.parse<valueof<T>>(data));
//if (data.length != 0) console.log(`Trailing-${data.slice(lastPos, len).trim()}-`)
return result;
}
export function parseDynamicObject(data: string): DynamicObject {
const len: u32 = data.length - 1
if (len === 1) return new DynamicObject()
const result = new Map<string, unknown>()
let lastPos: u32 = 1
let key: string = ''
let instr: u32 = 0
let char: u32 = 0
let depth: u32 = 0
let fdepth: u32 = 0
for (let i: u32 = 1; i < len; i++) {
char = data.charCodeAt(i)
if (char === quoteCode && data.charCodeAt(i - 1) !== fwd_slashCode) instr = (instr ? 0 : 1)
else if (instr === 0) {
if (char === lcbracketCode || char === lbracketCode) depth++
if (char === rcbracketCode || char === rbracketCode) fdepth++
}
if (depth !== 0 && depth === fdepth) {
result.set(key, unknown.wrap(data.slice(lastPos + 1, i + 1).trim()))
// Reset the depth
depth = 0
fdepth = 0
// Set new lastPos
lastPos = i + 2
}
if (depth === 0) {
if (char === colonCode) {
key = data.slice(lastPos + 1, i - 1).trim()
lastPos = i + 1
export function parseObject(data: string): void {
//const obj = instantiate<T>()
const result = new Array<string>();
let lastPos: u32 = 0;
let char: u32 = 0;
let i: u32 = 1;
let key: string = "";
let isKey: boolean = false;
for (; i < u32(data.length - 1); i++) {
char = data.charCodeAt(i);
if (isKey == false) {
if (char == colonCode) {
key = data.slice(lastPos + 2, i - 1);
//console.log(`Found Key: ${key}`);
result.push(key);
lastPos = ++i;
isKey = true;
}
else if (char === commaCode) {
if ((i - lastPos) > 0) result.set(key, unknown.wrap(data.slice(lastPos + 1, i).trim()))
lastPos = i + 1
} else {
if (char == commaCode) {
const val = data.slice(lastPos, i);
lastPos = i;
isKey = false;
//console.log(`Found Val: ${val}`)
result.push(val);
}
}
}
if ((len - lastPos) > 0) result.set(key, unknown.wrap(data.slice(lastPos + 1, len - 1).trim()))
const o = new DynamicObject()
// @ts-ignore
o.__data = result
return o
result.push(data.slice(lastPos, data.length - 1));
//console.log(stringify(result))
//return obj
}
export function removeJSONWhitespace(data: string): string {
let result = new StringSink()
let instr = false
let char = 0
for (let i = 0; i < data.length; i++) {
char = data.charCodeAt(i)
if (char === quoteCode && data.charCodeAt(i - 1) === fwd_slashCode) {
instr = !instr
}
if (instr === true) {
result.writeCodePoint(char)
} else if (instr === false && char !== empty_stringCode) {
result.writeCodePoint(char)
}
}
return result.toString()
}
class Nullable { }

@@ -1,207 +0,35 @@

import { unknown, unknownTypes } from './unknown'
import "wasi";
import { JSON } from ".";
import { console, stringify } from "../node_modules/as-console/assembly/wasi"
import { JSON, parseDynamicObject, parseUnknown, parseUnknownArray, removeJSONWhitespace } from '.'
import { DynamicObject } from './DynamicObject'
/*
// Not inlining results in an error for some reason
// @ts-ignore
@inline
function check<T>(message: string, data: T): void {
const encoded = JSON.stringify<T>(data)
const decoded = JSON.parse<T>(encoded)
if (encoded == JSON.stringify(decoded)) {
console.log(`Success: ${message}`)
} else {
console.log(`Fail: ${message}`)
}
}
// @ts-ignore
@json
class EmptySchema { }
// @ts-ignore
@json
class JSONSchema {
string1: string
string2: string
string3: string
f641: f64
f642: f64
f643: f64
f644: f64
f645: f64
f646: f64
f321: f32
f322: f32
f323: f32
f324: f32
f325: f32
f326: f32
u8: u8
u16: u16
u32: u32
u64: u64
i8: i8
i16: i16
i32: i32
i64: i64
bool: bool
boolean: boolean
stringArr: string[]
f64Arr: f64[]
u8Arr: u8[]
u16Arr: u16[]
u32Arr: u32[]
u64Arr: u64[]
i8Arr: i8[]
i16Arr: i16[]
i32Arr: i32[]
i64Arr: i64[]
emptyArr: string[]
boolArr: bool[]
booleanArr: boolean[]
stringArrArr: string[][]
object: JSONSchema2
class Vec2 {
x: f32
y: f32
}
// @ts-ignore
@json
class JSONSchema2 {
string1: string
class Player {
firstName: string
lastName: string
lastActive: i32[]
age: i32
pos: Vec2
}
const obj: JSONSchema = {
string1: 'Hello World',
string2: 'Hell[}o Wo[rld}{',
string3: 'Hel`"lo Wo"`r"ld',
f641: 7.23,
f642: 10e2,
f643: 10E2,
f644: 123456e-5,
f645: 123456E-5,
f646: 0.0,
f321: 7.23,
f322: 10e2,
f323: 10E2,
f324: 123456e-5,
f325: 123456E-5,
f326: 0.0,
u8: 100,
u16: 101,
u32: 102,
u64: 103,
i8: -100,
i16: -101,
i32: -102,
i64: -103,
bool: true,
boolean: false,
stringArr: ['Hello World', 'Hell[}o Wo[rld}{', 'Hel`"lo Wo"`r"ld'],
f64Arr: [7.23, 10e2, 10e2, 10E2, 123456e-5, 123456E-5, 0.0],
u8Arr: [100, 100, 100],
u16Arr: [101, 101, 101],
u32Arr: [102, 102, 102],
u64Arr: [103, 103, 103],
i8Arr: [-100, -100, -100],
i16Arr: [-101, -101, -101],
i32Arr: [-102, -102, -102],
i64Arr: [-103, -103, -103],
emptyArr: [],
boolArr: [true, false, true],
booleanArr: [true, false, true],
stringArrArr: [['Hey'], ['ha'], ['ho']],
object: {
string1: 'Hello World'
}
const data: Player = {
firstName: "Emmet",
lastName: "West",
lastActive: [8, 27, 2022],
age: 23,
pos: {
x: -3.4,
y: 1.2
}
}
const emptyObj: EmptySchema = {}
// Strings
check<string>('Encode/Decode String', 'Hello World')
check<string>('Encode/Decode String', 'Hell[}o Wo[rld}{')
check<string>('Encode/Decode String', 'Hel`"lo Wo"`r"ld')
// Floats
check<f64>('Encode/Decode f64', 7.23)
check<f64>('Encode/Decode f64', 10e2)
check<f64>('Encode/Decode f64', 10E2)
check<f64>('Encode/Decode f64', 123456e-5)
check<f64>('Encode/Decode f64', 123456E-5)
check<f64>('Encode/Decode f64', 0.0)
const stringified = JSON.stringify<Player>(data);
// '{"firstName":"Emmet","lastName":"West","lastActive":[8,27,2022],"age":23}'
console.log(`Stringified: ${stringified}`);
check<f32>('Encode/Decode f32', 7.23)
check<f32>('Encode/Decode f32', 10e2)
check<f32>('Encode/Decode f32', 10E2)
check<f32>('Encode/Decode f32', 123456e-5)
check<f32>('Encode/Decode f32', 123456E-5)
check<f32>('Encode/Decode f32', 0.0)
// Integers
check<u8>('Encode/Decode u8', 100)
check<u16>('Encode/Decode u16', 101)
check<u32>('Encode/Decode u32', 102)
check<u64>('Encode/Decode u64', 103)
check<i8>('Encode/Decode i8', -100)
check<i16>('Encode/Decode i16', -101)
check<i32>('Encode/Decode i32', -102)
check<i64>('Encode/Decode i64', -103)
// Bools
check<bool>('Encode/Decode bool', true)
check<bool>('Encode/Decode bool', false)
// Booleans
check<boolean>('Encode/Decode boolean', true)
check<boolean>('Encode/Decode boolean', false)
// Null
check('Encode/Decode null', null)
// Arrays
check<string[]>('Encode/Decode string[]', ['Hello World', 'Hell[}o Wo[rld}{', 'Hel`"lo Wo"`r"ld'])
check<f64[]>('Encode/Decode f32[]', [7.23, 10e2, 10e2, 10E2, 123456e-5, 123456E-5, 0.0])
check<u8[]>('Encode/Decode u8[]', [100, 100, 100])
check<u16[]>('Encode/Decode u16[]', [101, 101, 101])
check<u32[]>('Encode/Decode u32[]', [102, 102, 102])
check<u64[]>('Encode/Decode u64[]', [103, 103, 103])
check<i8[]>('Encode/Decode i8[]', [-100, -100, -100])
check<i16[]>('Encode/Decode i16[]', [-101, -101, -101])
check<i32[]>('Encode/Decode i32[]', [-102, -102, -102])
check<i64[]>('Encode/Decode i64[]', [-103, -103, -103])
check<string[]>('Encode/Decode empty[]', [])
check<bool[]>('Encode/Decode bool[]', [true, false, true])
check<boolean[]>('Encode/Decode boolean[]', [true, false, true])
check<string[][]>('Encode/Decode string[][]', [['Hey'], ['ha'], ['ho']])
// Object
check<JSONSchema>('Encode/Decode object', obj)
check<EmptySchema>('Encode/Decode object', emptyObj)
*/
// Unknown
//check<unknown[]>('Encode/Decode unknown[]', ["Welcome to dynamic arrays", ["Very", ["Deep", ["Array"]]], "It also supports nulls"])
//console.log(JSON.stringify(["Welcome to dynamic arrays", 3.14, ["Very", ["Deep", ["Array"]]], true, "It also supports nulls", null]))
//console.log(JSON.stringify(JSON.parse<unknown[]>('["Welcome to dynamic arrays",3.14,["Very",["Deep",["Array"]]],true,"It also supports nulls",null]')))
//const foo = new Map()
//console.log(JSON.stringify(parseDynamicObject('{"hello":"world"}')))
// @ts-ignore
@json
class Test {
stuff: string
things: i32
}
const test: Test = {
stuff: "hi",
things: 42
}
console.log(stringify(JSON.stringify(test)))
console.log(removeJSONWhitespace('{"stuff":"hi", "things":42}'))
console.log(stringify(JSON.stringify(JSON.parse<Test>('{"stuff":"hi", "things":42}'))))
const parsed = JSON.parse<Player>(stringified)
// { firstName: "Emmet", lastName: "West", "lastActive": [8,27,2022], age: 23 }
console.log(`Parsed: ${JSON.stringify(parsed)}`)
{
"name": "json-as",
"version": "0.2.6",
"version": "0.4.0",
"description": "JSON encoder/decoder for AssemblyScript",
"types": "assembly/index.ts",
"ascMain": "assembly/index.ts",
"author": "JairusSW",
"author": "Jairus Tanaka",
"contributors": [
"DogWhich"
],
"license": "MIT",
"scripts": {
"build:transform": "tsc -w -p ./transform",
"build:test": "asc assembly/test.ts --transform ./transform --target test --explicitStart",
"test": "node --experimental-wasi-unstable-preview1 ./tests/test",
"bench:build": "asc assembly/bench.ts --runtime incremental --transform ./transform --target bench --explicitStart",
"bench:node": "node --experimental-wasi-unstable-preview1 ./bench/bench",
"bench:wasmtime": "wasmtime ./bench/output/bench.wasm",
"bench:lunatic": "lunatic ./bench/output/bench.wasm",
"asbuild:untouched": "asc assembly/index.ts --target debug",
"asbuild:optimized": "asc assembly/index.ts --target release",
"asbuild": "yarn asbuild:untouched && yarn asbuild:optimized"
"bench:astral": "astral",
"build:test": "asc assembly/test.ts --target test",
"build:transform": "tsc -p ./transform",
"test:wasmtime": "wasmtime ./build/test.wasm",
"test:lunatic": "lunatic ./build/test.wasm",
"test:wasm3": "wasm3 ./build/test.wasm"
},
"devDependencies": {
"@as-pect/cli": "^6.2.4",
"@assemblyscript/loader": "^0.19.10",
"@serial-as/json": "^1.0.2",
"@types/jest": "^27.0.2",
"@types/line-column": "^1.0.0",
"as-base64": "^0.2.0",
"as-bignum": "^0.2.18",
"@as-tral/cli": "^1.1.1",
"as-console": "^6.0.2",
"as-variant": "^0.2.1",
"as-wasi": "^0.4.6",
"asbuild": "^0.2.0",
"assemblyscript": "^0.19.18",
"assemblyscript-json": "^1.1.0",
"jest": "^27.3.1",
"kati": "^0.6.2",
"lerna": "^4.0.0",
"rimraf": "^3.0.2",
"ts-jest": "^27.0.7",
"ts-node": "^10.4.0",
"typescript": "^4.4.4"
"assemblyscript": "^0.20.7",
"assemblyscript-prettier": "^1.0.2",
"benchmark": "^2.1.4",
"microtime": "^3.0.0",
"typescript": "^4.7.2"
},
"dependencies": {
"as-string-sink": "^0.4.2"
"as-string-sink": "^0.5.0",
"as-variant": "^0.3.0",
"visitor-as": "^0.10.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/aspkg/as-json.git"
"url": "git+https://github.com/JairusSW/as-json.git"
},

@@ -54,8 +41,10 @@ "keywords": [

"serialize",
"deserialize"
"deserialize",
"dynamic"
],
"bugs": {
"url": "https://github.com/aspkg/as-json/issues"
"url": "https://github.com/JairusSW/as-json/issues"
},
"homepage": "https://github.com/aspkg/as-json#readme"
"homepage": "https://github.com/JairusSW/as-json#readme",
"type": "module"
}
# AS-JSON
**JSON encoder/decoder for AssemblyScript**
**JSON serializer/deserializer for AssemblyScript**
## Installation

@@ -8,3 +9,8 @@

~ npm install json-as
~ yarn add json-as
~ bun install json-as
```
Add the transform to your `asc` command
```bash

@@ -14,115 +20,62 @@ --transform json-as/transform

## Support
- ✅ Objects
- ✅ Arrays
- ✅ Numbers
- ✅ Integers
- ✅ Null
- ✅ Dynamic Arrays
- ✅ Dynamic Types
- ✅ Dynamic Objects
- ✅ Whitespace
Or, add it to `asconfig.json`
## Usage
```js
import { JSON } from 'json-as'
```
**Object**
```js
@json
class JSONSchema {
firstName: string
lastName: string
age: i32
{
"options": {
"transform": "json-as/transform"
}
}
const data: JSONSchema {
firstName: 'Jairus',
lastName: 'Tanaka',
age: 14
}
const stringified = JSON.stringify(data)
// '{"firstName":"Jairus","lastName":"Tanaka","age":14}'
const parsed = JSON.parse<JSONSchema>(stringified)
// { firstName: "Jairus", lastName: "Tanaka", age: 14 }
```
**Array**
## Support
```js
const stringified = JSON.stringify(['Hello', 'World'])
// '["Hello","World"]'
- ✅ Objects (Supported)
- ✅ Arrays (Supported)
- ✅ Numbers (Supported)
- ✅ Integers (Supported)
- ✅ Null (Supported)
- ❌ Dynamic Variants (Not supported)
const parsed = JSON.parse<JSONSchema>(stringified)
// ["Hello", "World"]
```
## Usage
**Float**
```js
const stringified = JSON.stringify(3.14)
// '3.14'
import { JSON } from "json-as";
const parsed = JSON.parse<f64>(stringified)
// 3.14
```
@json
class Vec2 {
x: f32
y: f32
}
@json
class Player {
firstName: string
lastName: string
lastActive: i32[]
age: i32
pos: Vec2
}
**Integer**
const data: Player = {
firstName: "Emmet",
lastName: "West",
lastActive: [8, 27, 2022],
age: 23,
pos: {
x: -3.4,
y: 1.2
}
}
```js
const stringified = JSON.stringify(14)
// '14'
const stringified = JSON.stringify<Player>(data);
// '{"firstName":"Emmet","lastName":"West","lastActive":[8,27,2022],"age":23}'
console.log(`Stringified: ${stringified}`);
const parsed = JSON.parse<i32>(stringified)
// 14
const parsed = JSON.parse<Player>(stringified)
// { firstName: "Emmet", lastName: "West", "lastActive": [8,27,2022], age: 23 }
console.log(`Parsed: ${JSON.stringify(parsed)}`)
```
**Boolean**
## Issues
```js
const stringified = JSON.stringify(true)
// 'true'
const parsed = JSON.parse<boolean>(stringified)
// true
```
**Bool**
```js
const stringified = JSON.stringify(true)
// 'true'
const parsed = JSON.parse<bool>(stringified)
// true
```
**Null**
```js
const stringified = JSON.stringify(null)
// 'null'
const parsed = JSON.parse(stringified)
// null
```
## Benchmarks
```
AS-JSON Stringify String: ~4191267.51 ops/s | 23.86ms
AS-JSON Parse String: ~6218119.99 ops/s | 16.08ms
AS-JSON Stringify Integer: ~13775012.61 ops/s | 7.26ms
AS-JSON Parse Integer: ~55061164.13 ops/s | 1.82ms
AS-JSON Stringify Float: ~7739399.89 ops/s | 12.92ms
AS-JSON Parse Float: ~37522902.16 ops/s | 2.67ms
AS-JSON Stringify Boolean: ~615015015.02 ops/s | 0.16ms
AS-JSON Parse Boolean: ~93901879.87 ops/s | 1.06ms
AS-JSON Stringify Array: ~2380329.74 ops/s | 42.01ms
AS-JSON Parse Array: ~6258786.14 ops/s | 15.98ms
AS-JSON Stringify Object: ~5245632.91 ops/s | 19.06ms
AS-JSON Parse Object: ~1328576.06 ops/s | 75.27ms
```
Please submit an issue to https://github.com/JairusSW/as-json/issues if you find anything wrong with this library

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

const assert = require("assert");
const myModule = require("..");
assert.strictEqual(myModule.add(1, 2), 3);
import assert from "assert";
import { add } from "../build/debug.js";
assert.strictEqual(add(1, 2), 3);
console.log("ok");
const fs = require("fs");
const loader = require("@assemblyscript/loader");
const { WASI } = require('wasi')
const wasiOptions = {}
const wasi = new WASI(wasiOptions)
const { WASI } = require("wasi");
const ConsoleImport = require('as-console/imports')
const Console = new ConsoleImport()
const wasiOptions = {};
const wasi = new WASI(wasiOptions);
const imports = {
wasi_snapshot_preview1: wasi.wasiImport
wasi_snapshot_preview1: wasi.wasiImport,
...Console.wasmImports
};
const wasmModule = loader.instantiateSync(fs.readFileSync(__dirname + "/output/test.wasm"), imports);
wasi.start(wasmModule)
const wasmModule = loader.instantiateSync(
fs.readFileSync(__dirname + "/output/test.wasm"),
imports
);
Console.wasmExports = wasmModule.exports
wasi.start(wasmModule);

@@ -1,95 +0,29 @@

"use strict";
const as_1 = require("visitor-as/as");
const visitor_as_1 = require("visitor-as");
const utils_1 = require("visitor-as/dist/utils");
function getTypeName(type) {
let _type = (0, utils_1.getName)(type);
const OR_NULL = /\|.*null/;
if (type.isNullable && !OR_NULL.test(_type)) {
_type = `${_type} | null`;
import { ClassDecorator, registerDecorator } from "visitor-as/dist/decorator.js";
import { getName } from "visitor-as/dist/utils.js";
import { SimpleParser } from "visitor-as/dist/index.js";
class AsJSONTransform extends ClassDecorator {
constructor() {
super(...arguments);
this.sources = [];
this.encodeStmts = new Map();
this.decodeCode = new Map();
}
return _type;
}
// Replace Next Line
const replaceNextLineRegex = /^\W*\/\/ <replace next line>.*$/gm;
class JSONTransformer extends visitor_as_1.BaseVisitor {
currentClass;
encodeStmts = new Map();
decodeCode = new Map();
lastType = '';
sources = [];
globalStatements = [];
replaceNextLines = new Set();
visitObjectLiteralExpression(node) {
const keys = node.names;
const values = node.values;
const replacer = visitor_as_1.SimpleParser.parseExpression(`new Object()`);
for (const key of keys) {
}
}
visitElementAccessExpression(node) {
super.visitElementAccessExpression(node);
if ((0, utils_1.toString)(node.expression) === 'o') {
// Should be like if (node.expression.type.text === "Object") {
const replacer = visitor_as_1.SimpleParser.parseExpression(`u32(changetype<usize>(${(0, utils_1.toString)(node.elementExpression)}))`);
node.elementExpression = replacer;
this.sources.push(replacer.range.source);
}
}
visitArrayLiteralExpression(node) {
super.visitArrayLiteralExpression(node);
if (isanyArray(node)) {
for (let i = 0; i < node.elementExpressions.length; i++) {
const expr = node.elementExpressions[i];
// @ts-ignore
let replacement;
// @ts-ignore
if (expr.elementExpressions) {
// @ts-ignore
this.convertToAnyArray(expr.elementExpressions);
}
// @ts-ignore
replacement = visitor_as_1.SimpleParser.parseExpression(`unknown.wrap(${(0, utils_1.toString)(expr)})`);
node.elementExpressions[i] = replacement;
this.sources.push(replacement.range.source);
}
}
}
convertToAnyArray(exprs) {
for (let i = 0; i < exprs.length; i++) {
const expr = exprs[i];
// @ts-ignore
let replacement;
// @ts-ignore
if (expr.elementExpressions) {
// @ts-ignore
this.convertToAnyArray(expr.elementExpressions);
}
// @ts-ignore
replacement = visitor_as_1.SimpleParser.parseExpression(`unknown.wrap(${(0, utils_1.toString)(expr)})`);
exprs[i] = replacement;
this.sources.push(replacement.range.source);
}
}
visitMethodDeclaration(node) { }
visitFieldDeclaration(node) {
super.visitFieldDeclaration(node);
const name = (0, utils_1.toString)(node.name);
const name = getName(node);
if (!node.type) {
throw new Error(`Field ${name} is missing a type declaration`);
}
const type = getTypeName(node.type);
if (this.currentClass) {
const className = this.currentClass.name.text;
if (!this.encodeStmts.has(className))
this.encodeStmts.set(className, []);
if (!this.decodeCode.has(className))
this.decodeCode.set(className, []);
// @ts-ignore
this.encodeStmts.get(className).push(`this.__encoded += '' + '"' + '${name}' + '"' + ':' + JSON.stringify<${type}>(this.${name}) + ',';`);
// @ts-ignore
this.decodeCode.get(className).push(`${name}: JSON.parse<${type}>(unchecked(values.get('${name}'))),\n`);
}
const type = getName(node.type);
const className = this.currentClass.name.text;
if (!this.encodeStmts.has(className))
this.encodeStmts.set(className, []);
if (!this.decodeCode.has(className))
this.decodeCode.set(className, []);
// @ts-ignore
this.encodeStmts.get(className).push(`this.__JSON_Serialized += '' + '"' + '${name}' + '"' + ':' + JSON.stringify<${type}>(this.${name}) + ',';`);
// @ts-ignore
this.decodeCode.get(className).push(`${name}: JSON.parse<${type}>(values.get("${name}")),\n`);
}
visitClassDeclaration(node) {
super.visitClassDeclaration(node);
if (!node.members) {

@@ -99,16 +33,17 @@ return;

this.currentClass = node;
const name = (0, utils_1.getName)(node);
const name = getName(node);
this.encodeStmts.delete(name);
this.decodeCode.delete(name);
this.visit(node.members);
const encodedProp = `__encoded: string = ''`;
let encodeMethod = ``;
const serializedProp = `__JSON_Serialized: string = "";`;
let serializeFunc = ``;
if (this.encodeStmts.has(name) && this.encodeStmts.get(name)) {
encodeMethod = `
__encode(): void {
if (!this.__encoded) {
serializeFunc = `
__JSON_Serialize(): string {
if (!this.__JSON_Serialized) {
${ // @ts-ignore
this.encodeStmts.get(name).join("\n")};
this.__encoded = this.__encoded.slice(0, this.__encoded.length - 1)
this.__JSON_Serialized = "{" + this.__JSON_Serialized.slice(0, this.__JSON_Serialized.length - 1) + "}";
}
return this.__JSON_Serialized;
}

@@ -118,66 +53,28 @@ `;

else {
encodeMethod = `
__encode(): void {}
serializeFunc = `
__JSON_Serialize(): string {
return "{}";
}
`;
}
const decodeMethod = `
__decode(values: Map<string, string>): ${name} {
const decoded: ${name} = {
const deserializeFunc = `
__JSON_Deserialize(values: Map<string, string>): ${name} {
return {
${ // @ts-ignore
this.decodeCode.get(name) ? this.decodeCode.get(name).join("") : ''}
this.decodeCode.get(name) ? this.decodeCode.get(name).join("") : ""}
}
return decoded
}
`;
const encodedPropMember = visitor_as_1.SimpleParser.parseClassMember(encodedProp, node);
node.members.push(encodedPropMember);
const encodeMember = visitor_as_1.SimpleParser.parseClassMember(encodeMethod, node);
node.members.push(encodeMember);
const decodeMember = visitor_as_1.SimpleParser.parseClassMember(decodeMethod, node);
node.members.push(decodeMember);
//console.log(serializedProp, serializeFunc, deserializeFunc)
const serializedProperty = SimpleParser.parseClassMember(serializedProp, node);
node.members.push(serializedProperty);
const serializeMethod = SimpleParser.parseClassMember(serializeFunc, node);
node.members.push(serializeMethod);
const deserializeMethod = SimpleParser.parseClassMember(deserializeFunc, node);
node.members.push(deserializeMethod);
}
static visit(node) {
new JSONTransformer().visit(node);
get name() {
return "json";
}
visitSource(source) {
this.globalStatements = [];
super.visitSource(source);
}
}
function isanyArray(node) {
if (node.elementExpressions.length === 0)
return false;
const firstKind = node.elementExpressions[0]?.kind;
const isBoolean = ((0, utils_1.toString)(node.elementExpressions[0]) === 'true' || (0, utils_1.toString)(node.elementExpressions[0]) === 'false');
for (const chunk of node.elementExpressions) {
if (isBoolean) {
if ((0, utils_1.toString)(chunk) !== 'true' || (0, utils_1.toString)(chunk) !== 'false')
true;
}
else if (chunk.kind !== firstKind)
return true;
}
return false;
}
module.exports = class MyTransform extends as_1.Transform {
// Trigger the transform after parse.
afterParse(parser) {
// Create new transform
const transformer = new JSONTransformer();
// Loop over every source
for (const source of parser.sources) {
// Ignore all lib (std lib). Visit everything else.
if (!source.isLibrary && !source.internalPath.startsWith(`~lib/`)) {
transformer.visit(source);
}
}
let i = 0;
for (const source of transformer.sources) {
//source.internalPath += `${i++}.ts`
if (i === 0) {
parser.sources.push(source);
i++;
}
}
}
};
export default registerDecorator(new AsJSONTransform());
{
"main": "./lib/index.js"
}
"name": "@json-as/transform",
"version": "0.4.0",
"description": "JSON encoder/decoder for AssemblyScript",
"main": "./lib/index.js",
"author": "Jairus Tanaka",
"contributors": [
"DogWhich"
],
"license": "MIT",
"scripts": {},
"devDependencies": {},
"dependencies": {},
"repository": {
"type": "git",
"url": "git+https://github.com/JairusSW/as-json.git"
},
"keywords": [
"assemblyscript",
"json",
"serialize",
"deserialize",
"dynamic"
],
"bugs": {
"url": "https://github.com/JairusSW/as-json/issues"
},
"homepage": "https://github.com/JairusSW/as-json#readme",
"type": "module",
"exports": "./lib/index.js"
}
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
"declaration": false, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": false, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib/", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'unknown' type. */
"strictNullChecks": true, /* Enable strict null checks. */
"strictFunctionTypes": true, /* Enable strict checking of function types. */
"strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
"strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'unknown' type. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
"noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
"noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "es6" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
"declaration": false /* Generates corresponding '.d.ts' file. */,
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": false /* Generates corresponding '.map' file. */,
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
"downlevelIteration": true /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */,
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'Unknown' type. */,
"strictNullChecks": true /* Enable strict null checks. */,
"strictFunctionTypes": true /* Enable strict checking of function types. */,
"strictBindCallApply": true /* Enable strict 'bind', 'call', and 'apply' methods on functions. */,
"strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */,
"noImplicitThis": true /* Raise error on 'this' expressions with an implied 'Unknown' type. */,
"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
/* Additional Checks */
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
"noUncheckedIndexedAccess": true /* Include 'undefined' in index signature results */,
"noPropertyAccessFromIndexSignature": true /* Require undeclared properties from index signatures to use element accesses. */,
/* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": false /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}

Sorry, the diff of this file is not supported yet