From 4351de6702aa79e2d15d27b12af35a4e31f0b5b9 Mon Sep 17 00:00:00 2001 From: Jairus Date: Thu, 9 May 2024 18:31:26 -0700 Subject: [PATCH] dirty: fix #68 --- CHANGELOG | 3 +- assembly/src/json.ts | 123 ++++++++++++++++++++++++++++++++++------- assembly/test.ts | 18 +----- package.json | 2 +- transform/lib/index.js | 12 ++-- transform/package.json | 2 +- transform/src/index.ts | 12 ++-- 7 files changed, 121 insertions(+), 51 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b41efea..34a8fa9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1 +1,2 @@ -v0.8.2 - Properties starting with `static` or `private` would be ignored \ No newline at end of file +v0.8.2 - Properties starting with `static` or `private` would be ignored +v0.8.3 - Dirty fix to issue #68. Add __JSON_Stringify callable to global scope. \ No newline at end of file diff --git a/assembly/src/json.ts b/assembly/src/json.ts index 1a4e3cc..a5eb936 100644 --- a/assembly/src/json.ts +++ b/assembly/src/json.ts @@ -27,7 +27,7 @@ import { tabCode, formFeedCode, newLineCode, - + commaWord, quoteWord, @@ -50,7 +50,7 @@ export namespace JSON { /** * Stringifies valid JSON data. * ```js - * JSON.stringify(data) + * __JSON_Stringify(data) * ``` * @param data T * @returns string @@ -104,11 +104,11 @@ export namespace JSON { // @ts-ignore for (let i = 0; i < data.length - 1; i++) { // @ts-ignore - result.write(JSON.stringify(unchecked(data[i]))); + result.write(__JSON_Stringify(unchecked(data[i]))); result.writeCodePoint(commaCode); } // @ts-ignore - result.write(JSON.stringify(unchecked(data[data.length - 1]))); + result.write(__JSON_Stringify(unchecked(data[data.length - 1]))); result.writeCodePoint(rightBracketCode); return result.toString(); } @@ -116,14 +116,17 @@ export namespace JSON { let result = new StringSink(leftBraceWord); let keys = data.keys(); let values = data.values(); - for (let i = 0; i < data.size; i++) { + const end = data.size - 1; + for (let i = 0; i < end; i++) { result.write(serializeString(unchecked(keys[i]).toString())); result.writeCodePoint(colonCode); - result.write(JSON.stringify(unchecked(values[i]))); - if (i < data.size - 1) { - result.writeCodePoint(commaCode); - } + result.write(__JSON_Stringify(unchecked(values[i]))); + result.writeCodePoint(commaCode); } + result.write(serializeString(unchecked(keys[end]).toString())); + result.writeCodePoint(colonCode); + result.write(__JSON_Stringify(unchecked(values[end]))); + result.writeCodePoint(rightBraceCode); return result.toString(); } else { @@ -135,7 +138,7 @@ export namespace JSON { /** * Stringifies valid JSON data. * ```js - * JSON.stringify(data) + * __JSON_Stringify(data) * ``` * @param data T * @returns string @@ -198,11 +201,11 @@ export namespace JSON { // @ts-ignore for (let i = 0; i < data.length - 1; i++) { // @ts-ignore - result.write(JSON.stringify(unchecked(data[i]))); + result.write(__JSON_Stringify(unchecked(data[i]))); result.writeCodePoint(commaCode); } // @ts-ignore - result.write(JSON.stringify(unchecked(data[data.length - 1]))); + result.write(__JSON_Stringify(unchecked(data[data.length - 1]))); result.writeCodePoint(rightBracketCode); out = result.toString(); return; @@ -350,7 +353,7 @@ export namespace JSON { // @ts-ignore: Decorator @inline function parseString(data: string, start: i32 = 0, end: i32 = 0): string { - end = end || data.length - 1; + end = end || data.length - 1; let result = StringSink.withCapacity(end - start - 1); let last = start + 1; for (let i = last; i < end; i++) { @@ -444,7 +447,7 @@ export namespace JSON { const schema: nonnull = changetype>( __new(offsetof>(), idof>()) ); - + // @ts-ignore if (initializeDefaultValues) schema.__JSON_Initialize(); @@ -579,7 +582,7 @@ export namespace JSON { const map: nonnull = changetype>( __new(offsetof>(), idof>()) ); - + if (!isDefined(map.set)) { return unreachable(); } @@ -652,7 +655,7 @@ export namespace JSON { key.reinst(data, outerLoopIndex, stringValueIndex); } isKey = true; - } else { + } else { if (isString>()) { const value = parseString(data, outerLoopIndex - 1, stringValueIndex); map.set(parseMapKey>(key), value); @@ -702,7 +705,7 @@ export namespace JSON { if (char === colonCode || char === commaCode || char === rightBraceCode || isSpace(char)) { if (isFloat>() || isInteger>()) { map.set(parseMapKey>(key), parseNumber>(data.slice(outerLoopIndex - 1, numberValueIndex))); - } + } outerLoopIndex = numberValueIndex; isKey = false; break; @@ -754,7 +757,7 @@ export namespace JSON { return parseObjectArray(data); } } - + return unreachable(); } @@ -876,7 +879,7 @@ export namespace JSON { return result; } -function parseDate(dateTimeString: string): Date { +function parseDate(dateTimeString: string): Date { // Use AssemblyScript's date parser const d = Date.fromString(dateTimeString); @@ -891,3 +894,85 @@ function parseDate(dateTimeString: string): Date { let type = changetype(0); return type instanceof Map; } + +// Dirty fix + // @ts-ignore: Decorator +@global @inline function __JSON_Stringify(data: T): string { + // String + if (isString() && data != null) { + return serializeString(data as string); + } else if (isBoolean()) { + return data ? "true" : "false"; + } else if (isNullable() && data == null) { + return nullWord; + // @ts-ignore + } else if ((isInteger() || isFloat()) && isFinite(data)) { + // @ts-ignore + return data.toString(); + // @ts-ignore: Hidden function + } else if (isDefined(data.__JSON_Serialize)) { + // @ts-ignore: Hidden function + return data.__JSON_Serialize(); + } else if (data instanceof Date) { + return `"${data.toISOString()}"`; + } else if (isArrayLike()) { + // @ts-ignore + if (data.length == 0) { + return emptyArrayWord; + // @ts-ignore + } else if (isString>()) { + let result = leftBracketWord; + // @ts-ignore + for (let i = 0; i < data.length - 1; i++) { + // @ts-ignore + result += serializeString(unchecked(data[i])); + result += commaWord; + } + // @ts-ignore + result += serializeString(unchecked(data[data.length - 1])); + result += rightBracketWord; + return result; + // @ts-ignore + } else if (isBoolean>()) { + // @ts-ignore + return leftBracketWord + data.join(commaWord) + rightBracketWord; + // @ts-ignore + } else if (isFloat>() || isInteger>()) { + // @ts-ignore + return leftBracketWord + data.join(commaWord) + rightBracketWord; + } else { + 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.writeCodePoint(commaCode); + } + // @ts-ignore + result.write(__JSON_Stringify(unchecked(data[data.length - 1]))); + result.writeCodePoint(rightBracketCode); + return result.toString(); + } + } else if (data instanceof Map) { + let result = new StringSink(leftBraceWord); + let keys = data.keys(); + let values = data.values(); + const end = data.size - 1; + for (let i = 0; i < end; i++) { + result.write(serializeString(unchecked(keys[i]).toString())); + result.writeCodePoint(colonCode); + result.write(__JSON_Stringify(unchecked(values[i]))); + result.writeCodePoint(commaCode); + } + result.write(serializeString(unchecked(keys[end]).toString())); + result.writeCodePoint(colonCode); + result.write(__JSON_Stringify(unchecked(values[end]))); + + result.writeCodePoint(rightBraceCode); + return result.toString(); + } else { + throw new Error( + `Could not serialize data of type ${nameof()}. Make sure to add the correct decorators to classes.` + ); + } +} \ No newline at end of file diff --git a/assembly/test.ts b/assembly/test.ts index b403c20..24451ce 100644 --- a/assembly/test.ts +++ b/assembly/test.ts @@ -1,21 +1,5 @@ import { JSON } from "./src/json"; -@json -class Person { - staticprng: i32 = 23; - public country: string = ''; - - constructor(id: u32) { - this.staticprng = 321; - const seed = id.toString(); - this.country = this.getCountry(); - } - - // temp method, returns hard-coded string for now - private getCountry(): string { - return "USA"; - } -} - +import { Person } from "./p" const person = new Person(1); person.staticprng = 32 let result = JSON.stringify(person); diff --git a/package.json b/package.json index 3b04cd4..20dab65 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-as", - "version": "0.8.2", + "version": "0.8.3", "description": "JSON encoder/decoder for AssemblyScript", "types": "assembly/index.ts", "author": "Jairus Tanaka", diff --git a/transform/lib/index.js b/transform/lib/index.js index 9a0fd76..ae4caa6 100644 --- a/transform/lib/index.js +++ b/transform/lib/index.js @@ -123,7 +123,7 @@ class AsJSONTransform extends BaseVisitor { } } else { - this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${JSON.stringify<${type}>(this.${name})},`); + this.currentClass.encodeStmts.push(`${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})},`); // @ts-ignore this.currentClass.setDataStmts.push(`if (key.equals(${JSON.stringify(aliasName)})) { this.${name} = __parseObjectValue<${type}>(val_start ? data.slice(val_start, val_end) : data, initializeDefaultValues); @@ -194,11 +194,11 @@ class AsJSONTransform extends BaseVisitor { // // const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";'); // ... So we have to do it the long way: - const s = 'import { Virtual as __Virtual } from "as-virtual/assembly";'; - const t = new Tokenizer(new Source(0 /* SourceKind.User */, "index.ts", s)); - const p = new Parser(); - p.currentSource = t.source; - const stmt = p.parseTopLevelStatement(t); + const txt = 'import { Virtual as __Virtual } from "as-virtual/assembly";'; + const tokenizer = new Tokenizer(new Source(0 /* SourceKind.User */, node.normalizedPath, txt)); + const parser = new Parser(); + parser.currentSource = tokenizer.source; + const stmt = parser.parseTopLevelStatement(tokenizer); // Add the import statement to the top of the source. node.statements.unshift(stmt); } diff --git a/transform/package.json b/transform/package.json index cf1cce8..ad2f933 100644 --- a/transform/package.json +++ b/transform/package.json @@ -1,6 +1,6 @@ { "name": "@json-as/transform", - "version": "0.8.2", + "version": "0.8.3", "description": "JSON encoder/decoder for AssemblyScript", "main": "./lib/index.js", "author": "Jairus Tanaka", diff --git a/transform/src/index.ts b/transform/src/index.ts index a512887..f0ec014 100644 --- a/transform/src/index.ts +++ b/transform/src/index.ts @@ -156,7 +156,7 @@ class AsJSONTransform extends BaseVisitor { } } else { this.currentClass.encodeStmts.push( - `${encodeKey(aliasName)}:\${JSON.stringify<${type}>(this.${name})},` + `${encodeKey(aliasName)}:\${__JSON_Stringify<${type}>(this.${name})},` ); // @ts-ignore this.currentClass.setDataStmts.push( @@ -246,11 +246,11 @@ class AsJSONTransform extends BaseVisitor { // const stmt = SimpleParser.parseTopLevelStatement('import { Virtual as __Virtual } from "as-virtual/assembly";'); // ... So we have to do it the long way: - const s = 'import { Virtual as __Virtual } from "as-virtual/assembly";' - const t = new Tokenizer(new Source(SourceKind.User, "index.ts", s)); - const p = new Parser(); - p.currentSource = t.source; - const stmt = p.parseTopLevelStatement(t)!; + const txt = 'import { Virtual as __Virtual } from "as-virtual/assembly";' + const tokenizer = new Tokenizer(new Source(SourceKind.User, node.normalizedPath, txt)); + const parser = new Parser(); + parser.currentSource = tokenizer.source; + const stmt = parser.parseTopLevelStatement(tokenizer)!; // Add the import statement to the top of the source. node.statements.unshift(stmt);