Comparing version 0.9.23 to 0.9.24
@@ -1,7 +0,2 @@ | ||
import { bs } from "../custom/bs"; | ||
import { serializeBool, serializeBool_BS } from "../serialize/bool"; | ||
import { serialize_simd_v1, serializeString, serializeString_BS } from "../serialize/string"; | ||
const out = memory.data(65536); | ||
bench("UTF-16 to UTF-8", () => { | ||
@@ -8,0 +3,0 @@ blackbox<ArrayBuffer>(String.UTF8.encode(blackbox<string>("hello world"))); |
@@ -1,2 +0,1 @@ | ||
import { bs } from "../custom/bs"; | ||
import { | ||
@@ -3,0 +2,0 @@ CHAR_B, |
@@ -7,17 +7,5 @@ /** | ||
import { bs } from "../custom/bs"; | ||
// @ts-ignore: Decorator valid here | ||
@inline export function serializeBool(data: bool): string { | ||
return data ? "true" : "false"; | ||
} | ||
@inline export function serializeBool_BS(data: bool): void { | ||
if (data === true) { | ||
bs.write_64(28429475166421108); /* true */ | ||
} else { | ||
//bs.write_128_n(i16x8(102, 97, 108, 115, 101, 0, 0, 0), 10); | ||
bs.write_64(32370086184550502); /* fals */ | ||
bs.write_16(101); /* e */ | ||
} | ||
} |
@@ -1,12 +0,1 @@ | ||
import { | ||
BACK_SLASH, | ||
BACKSPACE, | ||
CARRIAGE_RETURN, | ||
FORM_FEED, | ||
NEW_LINE, | ||
QUOTE, | ||
TAB | ||
} from "../custom/chars"; | ||
import { OBJECT, TOTAL_OVERHEAD } from "rt/common"; | ||
import { bs } from "../custom/bs"; | ||
import { _intTo16, intTo16, unsafeCharCodeAt } from "../custom/util"; | ||
@@ -13,0 +2,0 @@ import { Sink } from "../custom/sink"; |
{ | ||
"name": "json-as", | ||
"version": "0.9.23", | ||
"version": "0.9.24", | ||
"description": "The only JSON library you'll need for AssemblyScript. SIMD enabled", | ||
@@ -47,2 +47,3 @@ "types": "assembly/index.ts", | ||
"dependencies": { | ||
"@hypermode/modus-sdk-as": "^0.13.0-prerelease-test-1", | ||
"as-virtual": "^0.2.0", | ||
@@ -49,0 +50,0 @@ "chalk": "^5.3.0" |
@@ -6,3 +6,3 @@ <h5 align="center"> | ||
|_____||_____||_____||_|___| |__|__||_____| | ||
v0.9.23 | ||
v0.9.24 | ||
</pre> | ||
@@ -9,0 +9,0 @@ </h5> |
@@ -1,14 +0,31 @@ | ||
import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js"; | ||
import { FieldDeclaration, IdentifierExpression, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, } from "assemblyscript/dist/assemblyscript.js"; | ||
import { toString, isStdlib } from "visitor-as/dist/utils.js"; | ||
import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js"; | ||
import { Transform } from "assemblyscript/dist/transform.js"; | ||
import chalk from "chalk"; | ||
const json_types = ["Array", "string", "String", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Map", "Date"]; | ||
class JSONTransform extends BaseVisitor { | ||
types = json_types; | ||
schemasList = []; | ||
currentClass; | ||
sources = new Set(); | ||
appendParentFields(node, schema, members) { | ||
visitMethodDeclaration() { } | ||
visitClassDeclaration(node) { | ||
if (!node.decorators?.length) | ||
return; | ||
let found = false; | ||
for (const decorator of node.decorators) { | ||
const name = decorator.name.text; | ||
if (name === "json" || name === "serializable") { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (!found) | ||
return; | ||
const schema = new SchemaData(); | ||
schema.node = node; | ||
schema.name = node.name.text; | ||
const members = [ | ||
...node.members.filter((v) => v.kind === 54 /* NodeKind.FieldDeclaration */), | ||
]; | ||
if (node.extendsType) { | ||
schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text); | ||
if (schema.parent?.members) { | ||
@@ -21,55 +38,36 @@ for (let i = schema.parent.members.length - 1; i >= 0; i--) { | ||
} | ||
this.appendParentFields(schema.parent.node, schema, members); | ||
} | ||
} | ||
} | ||
handleEmptyClass(node, schema, members) { | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
let SERIALIZE_PRETTY_EMPTY = '__SERIALIZE_PRETTY(): string {\n return "{}";\n}'; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); | ||
const SERIALIZE_PRETTY_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_PRETTY_EMPTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) | ||
node.members.push(SERIALIZE_PRETTY_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
} | ||
filterMembers(members) { | ||
return members.filter((v) => v instanceof FieldDeclaration && !v.decorators?.find((v) => v.name.text == "omit")); | ||
} | ||
visitClassDeclaration(node) { | ||
if (!node.decorators?.length) | ||
return; | ||
if (!node.decorators.find((v) => v.name.text == "json" || v.name.text == "serializable")) | ||
return; | ||
this.types = json_types; | ||
const schema = new SchemaData(); | ||
schema.node = node; | ||
schema.name = node.name.text; | ||
if (node.extendsType) { | ||
schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text); | ||
} | ||
const _members = [...node.members]; | ||
this.appendParentFields(node, schema, _members); | ||
const members = this.filterMembers(_members); | ||
if (!members.length) { | ||
this.handleEmptyClass(node, schema, members); | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
//let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}"; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
//console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
this.schemasList.push(schema); | ||
} | ||
for (const member of members) { | ||
const name = member.name; | ||
if (!(member instanceof FieldDeclaration)) | ||
continue; | ||
if (!member.type) { | ||
throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath); | ||
throw new Error("Fields must be strongly typed! Found " + | ||
toString(member) + | ||
" at " + | ||
node.range.source.normalizedPath); | ||
} | ||
@@ -104,3 +102,4 @@ const type = toString(member.type); | ||
if (!args.length) | ||
throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath); | ||
throw new Error("Expected 1 argument but got zero at @alias in " + | ||
node.range.source.normalizedPath); | ||
mem.alias = args[0]; | ||
@@ -116,3 +115,4 @@ mem.flags.set(PropertyFlags.Alias, args); | ||
if (!decorator.args?.length) | ||
throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath); | ||
throw new Error("Expected 1 argument but got zero at @omitif in " + | ||
node.range.source.normalizedPath); | ||
mem.flags.set(PropertyFlags.OmitIf, args); | ||
@@ -128,6 +128,18 @@ break; | ||
} | ||
if (!mem.flags.get(PropertyFlags.Omit)) | ||
mem.generate(); | ||
mem.generate(); | ||
if (this.schemasList.find((v) => v.name == type)) { | ||
mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()"; | ||
mem.initialize = | ||
"this." + | ||
name.text + | ||
" = changetype<nonnull<" + | ||
mem.type + | ||
">>(__new(offsetof<nonnull<" + | ||
mem.type + | ||
">>(), idof<nonnull<" + | ||
mem.type + | ||
">>()));\n changetype<nonnull<" + | ||
mem.type + | ||
">>(this." + | ||
name.text + | ||
").__INITIALIZE()"; | ||
} | ||
@@ -144,3 +156,4 @@ else if (mem.value) { | ||
else if (type === "Array") { | ||
mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
mem.initialize = | ||
"this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
} | ||
@@ -153,3 +166,10 @@ else if (type === "bool" || type === "boolean") { | ||
} | ||
else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") { | ||
else if (type === "u8" || | ||
type === "u16" || | ||
type === "u32" || | ||
type === "u64" || | ||
type === "i8" || | ||
type === "i16" || | ||
type === "i32" || | ||
type === "i64") { | ||
mem.initialize = "this." + name.text + " = 0"; | ||
@@ -169,10 +189,11 @@ } | ||
return; | ||
let found = false; | ||
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { | ||
found = false; | ||
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || | ||
schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { | ||
SERIALIZE_RAW += schema.members[0]?.serialize; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize; | ||
} | ||
else { | ||
SERIALIZE_RAW += schema.members[0]?.serialize + ","; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n"; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n"; | ||
found = true; | ||
@@ -186,11 +207,10 @@ } | ||
INITIALIZE += " " + member.initialize + ";\n"; | ||
if (member.flags.has(PropertyFlags.Omit)) | ||
continue; | ||
if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) { | ||
if (member.flags.has(PropertyFlags.OmitNull) || | ||
member.flags.has(PropertyFlags.OmitIf)) { | ||
SERIALIZE_RAW += member.serialize; | ||
SERIALIZE_PRETTY += member.serialize_pretty; | ||
SERIALIZE_PRETTY += member.serialize; | ||
} | ||
else { | ||
SERIALIZE_RAW += member.serialize + ","; | ||
SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n"; | ||
SERIALIZE_PRETTY += indent + member.serialize + ",\\n"; | ||
found = true; | ||
@@ -200,4 +220,6 @@ } | ||
if (found) { | ||
SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
SERIALIZE_RAW += | ||
"`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += | ||
"`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
} | ||
@@ -231,7 +253,9 @@ else { | ||
if (first) { | ||
DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
" if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} | ||
else { | ||
DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
"else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
@@ -241,7 +265,9 @@ } | ||
if (first) { | ||
DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
" if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} | ||
else { | ||
DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
"else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
@@ -251,7 +277,9 @@ } | ||
if (first) { | ||
DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += | ||
" if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
first = false; | ||
} | ||
else { | ||
DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += | ||
"else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
} | ||
@@ -286,3 +314,5 @@ } | ||
else { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
`else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -296,3 +326,5 @@ } | ||
else { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -305,6 +337,10 @@ } | ||
else if (_name.length == 4) { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
} | ||
else { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
} | ||
@@ -317,3 +353,3 @@ DESERIALIZE += " } "; | ||
console.log(SERIALIZE_RAW); | ||
console.log(SERIALIZE_PRETTY); | ||
//console.log(SERIALIZE_PRETTY); | ||
console.log(INITIALIZE); | ||
@@ -323,3 +359,3 @@ console.log(DESERIALIZE); | ||
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node); | ||
const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node); | ||
@@ -329,4 +365,2 @@ const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node); | ||
node.members.push(SERIALIZE_RAW_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) | ||
node.members.push(SERIALIZE_PRETTY_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
@@ -357,9 +391,11 @@ node.members.push(INITIALIZE_METHOD); | ||
const b = _b.internalPath; | ||
if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} | ||
if (a[0] === "~" && b[0] !== "~") { | ||
return -1; | ||
} | ||
return 0; | ||
else if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} | ||
else { | ||
return 0; | ||
} | ||
}); | ||
@@ -376,6 +412,6 @@ // Loop over every source | ||
for (const schema of schemas) { | ||
checkInheritance(schema, schemas); | ||
const invalidType = checkTypeCorrectness(schema, schemas); | ||
if (invalidType) { | ||
logError(`Type ${invalidType.type} implemented in property ${invalidType.path} is not a JSON-compatible type!\nEither decorate it with @omit or fix it!`); | ||
if (schema.parent) { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
if (!parent) | ||
throw new Error(`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`); | ||
} | ||
@@ -385,58 +421,2 @@ } | ||
} | ||
function checkInheritance(schema, schemas) { | ||
if (!schema.parent && schema.node.extendsType) { | ||
if (schemas.find(v => v.node.name.text === schema.node.extendsType?.name.identifier.text)) | ||
return; | ||
const extending = toString(schema.node.extendsType); | ||
logError(`Schema ${schema.name} extends ${extending}, but ${extending} does not include the @json decorator!`); | ||
} | ||
} | ||
function checkTypeCorrectness(schema, schemas) { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
const generic_types = [...(schema?.node.typeParameters?.map((v) => v.name.text) || []), ...(parent?.node.typeParameters?.map((v) => v.name.text) || [])]; | ||
const member_types = [...(schema.members.map((v) => v.node.type.name.identifier.text) || [])]; | ||
const scopeTypes = new Set([...json_types, ...generic_types, ...member_types]); | ||
for (const typ of member_types) { | ||
if (typ === "JSON") | ||
continue; // JSON.Raw, JSON.Box, JSON.Any, ect... | ||
if (json_types.includes(typ)) | ||
continue; | ||
if (generic_types.includes(typ)) | ||
continue; | ||
const check = schemas.find((v) => v.name == typ); | ||
if (!check) | ||
logError(`Type ${typ} is not a JSON compatible type or does not include the @json flag!`); | ||
} | ||
for (const member of schema.members) { | ||
const invalidType = checkType(schema, schemas, member.node.type, member, scopeTypes, schema.name); | ||
if (invalidType) | ||
logError(`Type ${invalidType.type} in ${invalidType.path} does not implement a JSON compatible type!\n${chalk.dim(` at ${member.node.range.source.normalizedPath.replace("~lib/", "./node_modules/")}`)}`); | ||
} | ||
return null; | ||
} | ||
function checkType(schema, schemas, typ, member, scopeTypes, path) { | ||
path += "." + member.name; | ||
if (schemas.find(v => v.node.name.text === typ.name.identifier.text)) | ||
scopeTypes.add(typ.name.identifier.text); | ||
if (!scopeTypes.has(typ.name.identifier.text)) | ||
return { type: toString(typ), path }; | ||
if (typ.isNullable && isPrimitive(typ)) | ||
return { type: toString(typ), path }; | ||
if (typ.typeArguments?.length && typ.typeArguments?.length > 0) { | ||
for (const ty of typ.typeArguments.filter((v) => v instanceof NamedTypeNode)) { | ||
const check = checkType(schema, schemas, ty, member, scopeTypes, path); | ||
if (check) | ||
return { type: toString(typ), path }; | ||
} | ||
} | ||
else { | ||
if (scopeTypes.has(typ.name.identifier.text)) | ||
return null; | ||
} | ||
return null; | ||
} | ||
function logError(message) { | ||
console.log("\n" + chalk.bold.bgRed(" Error ") + chalk.dim(":") + " " + message + "\n"); | ||
process.exit(1); | ||
} | ||
var PropertyFlags; | ||
@@ -458,3 +438,2 @@ (function (PropertyFlags) { | ||
serialize = null; | ||
serialize_pretty = null; | ||
deserialize = null; | ||
@@ -473,3 +452,3 @@ initialize = null; | ||
if (this.flags.has(PropertyFlags.Null)) { | ||
this.right_s = "(this." + name + ' || "null")'; | ||
this.right_s = "(this." + name + " || \"null\")"; | ||
this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)"; | ||
@@ -484,3 +463,4 @@ } | ||
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")"; | ||
this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
this.right_d = | ||
"__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
} | ||
@@ -491,9 +471,22 @@ if (this.flags.has(PropertyFlags.OmitIf)) { | ||
throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition"); | ||
this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
this.serialize = | ||
"${" + | ||
condition + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
} | ||
else if (this.flags.has(PropertyFlags.OmitNull)) { | ||
this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
this.serialize = | ||
"${changetype<usize>(this." + | ||
name + | ||
") == <usize>0" + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
@@ -503,3 +496,2 @@ } | ||
this.serialize = escapedName + ":${" + this.right_s + "}"; | ||
this.serialize_pretty = escapedName + ": ${" + this.right_s + "}"; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
@@ -526,3 +518,6 @@ } | ||
const fourthCharCode = BigInt(data.charCodeAt(offset + 3)); | ||
const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode; | ||
const u64Value = (fourthCharCode << 48n) | | ||
(thirdCharCode << 32n) | | ||
(secondCharCode << 16n) | | ||
firstCharCode; | ||
return u64Value; | ||
@@ -572,5 +567,1 @@ } | ||
} | ||
function isPrimitive(type) { | ||
const primitives = new Set(["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean"]); | ||
return primitives.has(type.name.identifier.text); | ||
} |
{ | ||
"name": "@json-as/transform", | ||
"version": "0.9.23", | ||
"version": "0.9.24", | ||
"description": "The only JSON library you'll need for AssemblyScript. SIMD enabled", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
@@ -1,2 +0,17 @@ | ||
import { ClassDeclaration, FieldDeclaration, IdentifierExpression, Parser, Source, Expression, CommonFlags, StringLiteralExpression, IntegerLiteralExpression, FloatLiteralExpression, NullExpression, TrueExpression, FalseExpression, DeclarationStatement, NamedTypeNode } from "assemblyscript/dist/assemblyscript.js"; | ||
import { | ||
ClassDeclaration, | ||
FieldDeclaration, | ||
IdentifierExpression, | ||
Parser, | ||
Source, | ||
NodeKind, | ||
Expression, | ||
CommonFlags, | ||
StringLiteralExpression, | ||
IntegerLiteralExpression, | ||
FloatLiteralExpression, | ||
NullExpression, | ||
TrueExpression, | ||
FalseExpression, | ||
} from "assemblyscript/dist/assemblyscript.js"; | ||
@@ -6,8 +21,4 @@ import { toString, isStdlib } from "visitor-as/dist/utils.js"; | ||
import { Transform } from "assemblyscript/dist/transform.js"; | ||
import chalk from "chalk"; | ||
const json_types = ["Array", "string", "String", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean", "Map", "Date"]; | ||
class JSONTransform extends BaseVisitor { | ||
public types = json_types; | ||
public schemasList: SchemaData[] = []; | ||
@@ -17,7 +28,34 @@ public currentClass!: SchemaData; | ||
appendParentFields(node: ClassDeclaration, schema: SchemaData, members: DeclarationStatement[]): void { | ||
visitMethodDeclaration(): void { } | ||
visitClassDeclaration(node: ClassDeclaration): void { | ||
if (!node.decorators?.length) return; | ||
let found = false; | ||
for (const decorator of node.decorators) { | ||
const name = (<IdentifierExpression>decorator.name).text; | ||
if (name === "json" || name === "serializable") { | ||
found = true; | ||
break; | ||
} | ||
} | ||
if (!found) return; | ||
const schema = new SchemaData(); | ||
schema.node = node; | ||
schema.name = node.name.text; | ||
const members = [ | ||
...node.members.filter((v) => v.kind === NodeKind.FieldDeclaration), | ||
]; | ||
if (node.extendsType) { | ||
schema.parent = this.schemasList.find( | ||
(v) => v.name == node.extendsType?.name.identifier.text, | ||
) as SchemaData | null; | ||
if (schema.parent?.members) { | ||
for (let i = schema.parent.members.length - 1; i >= 0; i--) { | ||
const replace = schema.members.find((v) => v.name == schema.parent?.members[i]?.name); | ||
const replace = schema.members.find( | ||
(v) => v.name == schema.parent?.members[i]?.name, | ||
); | ||
if (!replace) { | ||
@@ -27,64 +65,56 @@ members.unshift(schema.parent?.members[i]!.node); | ||
} | ||
this.appendParentFields(schema.parent.node, schema, members); | ||
} | ||
} | ||
} | ||
handleEmptyClass(node: ClassDeclaration, schema: SchemaData, members: DeclarationStatement[]): void { | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
let SERIALIZE_PRETTY_EMPTY = '__SERIALIZE_PRETTY(): string {\n return "{}";\n}'; | ||
if (!members.length) { | ||
let SERIALIZE_RAW_EMPTY = '__SERIALIZE(): string {\n return "{}";\n}'; | ||
//let SERIALIZE_PRETTY_EMPTY = "__SERIALIZE_PRETTY(): string {\n return \"{}\";\n}"; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; | ||
let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
let DESERIALIZE_EMPTY = | ||
"__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
if (process.env["JSON_DEBUG"]) { | ||
console.log(SERIALIZE_RAW_EMPTY); | ||
//console.log(SERIALIZE_PRETTY_EMPTY); | ||
console.log(INITIALIZE_EMPTY); | ||
console.log(DESERIALIZE_EMPTY); | ||
} | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); | ||
const SERIALIZE_PRETTY_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_PRETTY_EMPTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); | ||
const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember( | ||
SERIALIZE_RAW_EMPTY, | ||
node, | ||
); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember( | ||
INITIALIZE_EMPTY, | ||
node, | ||
); | ||
const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember( | ||
DESERIALIZE_EMPTY, | ||
node, | ||
); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) node.members.push(SERIALIZE_PRETTY_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
} | ||
filterMembers(members: DeclarationStatement[]): FieldDeclaration[] { | ||
return members.filter((v) => v instanceof FieldDeclaration && !v.decorators?.find((v) => (<IdentifierExpression>v.name).text == "omit")) as FieldDeclaration[]; | ||
} | ||
visitClassDeclaration(node: ClassDeclaration): void { | ||
if (!node.decorators?.length) return; | ||
if (!node.decorators.find((v) => (<IdentifierExpression>v.name).text == "json" || (<IdentifierExpression>v.name).text == "serializable")) return; | ||
this.types = json_types; | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD_EMPTY); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD_EMPTY); | ||
const schema = new SchemaData(); | ||
schema.node = node; | ||
schema.name = node.name.text; | ||
if (node.extendsType) { | ||
schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text) as SchemaData | null; | ||
this.schemasList.push(schema); | ||
} | ||
const _members = [...node.members]; | ||
this.appendParentFields(node, schema, _members); | ||
const members = this.filterMembers(_members); | ||
if (!members.length) { | ||
this.handleEmptyClass(node, schema, members); | ||
} | ||
for (const member of members) { | ||
const name = member.name; | ||
if (!(member instanceof FieldDeclaration)) continue; | ||
if (!member.type) { | ||
throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath); | ||
throw new Error( | ||
"Fields must be strongly typed! Found " + | ||
toString(member) + | ||
" at " + | ||
node.range.source.normalizedPath, | ||
); | ||
} | ||
const type = toString(member.type!); | ||
@@ -120,3 +150,7 @@ if (type.startsWith("(") && type.includes("=>")) continue; | ||
case "alias": { | ||
if (!args.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath); | ||
if (!args.length) | ||
throw new Error( | ||
"Expected 1 argument but got zero at @alias in " + | ||
node.range.source.normalizedPath, | ||
); | ||
mem.alias = args[0]!; | ||
@@ -131,3 +165,7 @@ mem.flags.set(PropertyFlags.Alias, args); | ||
case "omitif": { | ||
if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath); | ||
if (!decorator.args?.length) | ||
throw new Error( | ||
"Expected 1 argument but got zero at @omitif in " + | ||
node.range.source.normalizedPath, | ||
); | ||
mem.flags.set(PropertyFlags.OmitIf, args); | ||
@@ -144,6 +182,19 @@ break; | ||
if (!mem.flags.get(PropertyFlags.Omit)) mem.generate(); | ||
mem.generate(); | ||
if (this.schemasList.find((v) => v.name == type)) { | ||
mem.initialize = "this." + name.text + " = changetype<nonnull<" + mem.type + ">>(__new(offsetof<nonnull<" + mem.type + ">>(), idof<nonnull<" + mem.type + ">>()));\n changetype<nonnull<" + mem.type + ">>(this." + name.text + ").__INITIALIZE()"; | ||
mem.initialize = | ||
"this." + | ||
name.text + | ||
" = changetype<nonnull<" + | ||
mem.type + | ||
">>(__new(offsetof<nonnull<" + | ||
mem.type + | ||
">>(), idof<nonnull<" + | ||
mem.type + | ||
">>()));\n changetype<nonnull<" + | ||
mem.type + | ||
">>(this." + | ||
name.text + | ||
").__INITIALIZE()"; | ||
} else if (mem.value) { | ||
@@ -156,3 +207,4 @@ mem.initialize = "this." + name.text + " = " + mem.value; | ||
} else if (type === "Array") { | ||
mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
mem.initialize = | ||
"this." + name.text + " = instantiate<" + mem.type + ">()"; | ||
} else if (type === "bool" || type === "boolean") { | ||
@@ -162,3 +214,12 @@ mem.initialize = "this." + name.text + " = false"; | ||
mem.initialize = "this." + name.text + ' = ""'; | ||
} else if (type === "u8" || type === "u16" || type === "u32" || type === "u64" || type === "i8" || type === "i16" || type === "i32" || type === "i64") { | ||
} else if ( | ||
type === "u8" || | ||
type === "u16" || | ||
type === "u32" || | ||
type === "u64" || | ||
type === "i8" || | ||
type === "i16" || | ||
type === "i32" || | ||
type === "i64" | ||
) { | ||
mem.initialize = "this." + name.text + " = 0"; | ||
@@ -177,3 +238,4 @@ } else if (type === "f32" || type === "f64") { | ||
let DESERIALIZE = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n"; | ||
let DESERIALIZE = | ||
"__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n"; | ||
let indent = " "; | ||
@@ -183,14 +245,18 @@ | ||
let found = false; | ||
found = false; | ||
if (schema.members[0]?.flags.has(PropertyFlags.OmitNull) || schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { | ||
if ( | ||
schema.members[0]?.flags.has(PropertyFlags.OmitNull) || | ||
schema.members[0]?.flags.has(PropertyFlags.OmitIf) | ||
) { | ||
SERIALIZE_RAW += schema.members[0]?.serialize; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize; | ||
} else { | ||
SERIALIZE_RAW += schema.members[0]?.serialize + ","; | ||
SERIALIZE_PRETTY += "\\n" + indent + schema.members[0]?.serialize_pretty + ",\\n"; | ||
SERIALIZE_PRETTY += "\\n" + schema.members[0]?.serialize + ",\\n"; | ||
found = true; | ||
} | ||
if (schema.members[0]?.initialize) INITIALIZE += " " + schema.members[0]?.initialize + ";\n"; | ||
if (schema.members[0]?.initialize) | ||
INITIALIZE += " " + schema.members[0]?.initialize + ";\n"; | ||
@@ -200,9 +266,11 @@ for (let i = 1; i < schema.members.length; i++) { | ||
if (member.initialize) INITIALIZE += " " + member.initialize + ";\n"; | ||
if (member.flags.has(PropertyFlags.Omit)) continue; | ||
if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) { | ||
if ( | ||
member.flags.has(PropertyFlags.OmitNull) || | ||
member.flags.has(PropertyFlags.OmitIf) | ||
) { | ||
SERIALIZE_RAW += member.serialize; | ||
SERIALIZE_PRETTY += member.serialize_pretty; | ||
SERIALIZE_PRETTY += member.serialize; | ||
} else { | ||
SERIALIZE_RAW += member.serialize + ","; | ||
SERIALIZE_PRETTY += indent + member.serialize_pretty + ",\\n"; | ||
SERIALIZE_PRETTY += indent + member.serialize + ",\\n"; | ||
found = true; | ||
@@ -213,4 +281,6 @@ } | ||
if (found) { | ||
SERIALIZE_RAW += "`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += "`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
SERIALIZE_RAW += | ||
"`;\n store<u16>(changetype<usize>(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; | ||
SERIALIZE_PRETTY += | ||
"`;\n store<u32>(changetype<usize>(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; | ||
} else { | ||
@@ -224,3 +294,5 @@ SERIALIZE_RAW += "}`;\n return out;\n}"; | ||
const sortedMembers: Property[][] = []; | ||
const _sorted = schema.members.sort((a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length)); | ||
const _sorted = schema.members.sort( | ||
(a, b) => (a.alias?.length! || a.name.length) - (b.alias?.length! || b.name.length), | ||
); | ||
let len = -1; | ||
@@ -246,20 +318,26 @@ let offset = -1; | ||
if (first) { | ||
DESERIALIZE += " if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
" if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} else { | ||
DESERIALIZE += "else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
"else if (1 === len) {\n switch (load<u16>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
} else if (_name.length === 2) { | ||
if (first) { | ||
DESERIALIZE += " if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
" if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
first = false; | ||
} else { | ||
DESERIALIZE += "else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
DESERIALIZE += | ||
"else if (2 === len) {\n switch (load<u32>(changetype<usize>(data) + (key_start << 1))) {\n"; | ||
} | ||
} else if (_name.length === 4) { | ||
if (first) { | ||
DESERIALIZE += " if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += | ||
" if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
first = false; | ||
} else { | ||
DESERIALIZE += "else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
DESERIALIZE += | ||
"else if (4 === len) {\n const code = load<u64>(changetype<usize>(data) + (key_start << 1));\n"; | ||
} | ||
@@ -288,3 +366,5 @@ } else { | ||
} else { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
`else if (${charCodeAt64(_name, 0)} === code) {\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -296,3 +376,5 @@ } else { | ||
} else { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else if (0 === memory.compare(changetype<usize>("${escapeQuote(escapeSlash(_name))}"), changetype<usize>(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; | ||
} | ||
@@ -304,5 +386,9 @@ } | ||
} else if (_name.length == 4) { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
} else { | ||
DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; | ||
DESERIALIZE = | ||
DESERIALIZE.slice(0, DESERIALIZE.length - 1) + | ||
` else {\n return false;\n }\n`; | ||
} | ||
@@ -318,3 +404,3 @@ DESERIALIZE += " } "; | ||
console.log(SERIALIZE_RAW); | ||
console.log(SERIALIZE_PRETTY); | ||
//console.log(SERIALIZE_PRETTY); | ||
console.log(INITIALIZE); | ||
@@ -324,11 +410,16 @@ console.log(DESERIALIZE); | ||
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node); | ||
const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember( | ||
SERIALIZE_RAW, | ||
node, | ||
); | ||
//const SERIALIZE_PRETTY_METHOD = SimpleParser.parseClassMember(SERIALIZE_PRETTY, node); | ||
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node); | ||
const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE_PRETTY")) node.members.push(SERIALIZE_PRETTY_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__SERIALIZE")) | ||
node.members.push(SERIALIZE_RAW_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__INITIALIZE")) | ||
node.members.push(INITIALIZE_METHOD); | ||
if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) | ||
node.members.push(DESERIALIZE_METHOD); | ||
@@ -359,9 +450,9 @@ this.schemasList.push(schema); | ||
const b = _b.internalPath; | ||
if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} | ||
if (a[0] === "~" && b[0] !== "~") { | ||
return -1; | ||
} else if (a[0] !== "~" && b[0] === "~") { | ||
return 1; | ||
} else { | ||
return 0; | ||
} | ||
return 0; | ||
}); | ||
@@ -379,6 +470,8 @@ | ||
for (const schema of schemas) { | ||
checkInheritance(schema, schemas); | ||
const invalidType = checkTypeCorrectness(schema, schemas); | ||
if (invalidType) { | ||
logError(`Type ${invalidType.type} implemented in property ${invalidType.path} is not a JSON-compatible type!\nEither decorate it with @omit or fix it!`); | ||
if (schema.parent) { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
if (!parent) | ||
throw new Error( | ||
`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`, | ||
); | ||
} | ||
@@ -389,72 +482,2 @@ } | ||
function checkInheritance(schema: SchemaData, schemas: SchemaData[]): void { | ||
if (!schema.parent && schema.node.extendsType) { | ||
if (schemas.find(v => v.node.name.text === schema.node.extendsType?.name.identifier.text!)) return; | ||
const extending = toString(schema.node.extendsType); | ||
logError(`Schema ${schema.name} extends ${extending}, but ${extending} does not include the @json decorator!`); | ||
} | ||
} | ||
function checkTypeCorrectness( | ||
schema: SchemaData, | ||
schemas: SchemaData[] | ||
): { | ||
type: string; | ||
path: string; | ||
} | null { | ||
const parent = schemas.find((v) => v.name === schema.parent?.name); | ||
const generic_types = [...(schema?.node.typeParameters?.map<string>((v) => v.name.text) || []), ...(parent?.node.typeParameters?.map<string>((v) => v.name.text) || [])]; | ||
const member_types = [...(schema.members.map((v) => (<NamedTypeNode>v.node.type).name.identifier.text) || [])]; | ||
const scopeTypes = new Set<string>([...json_types, ...generic_types, ...member_types]); | ||
for (const typ of member_types) { | ||
if (typ === "JSON") continue; // JSON.Raw, JSON.Box, JSON.Any, ect... | ||
if (json_types.includes(typ)) continue; | ||
if (generic_types.includes(typ)) continue; | ||
const check = schemas.find((v) => v.name == typ); | ||
if (!check) logError(`Type ${typ} is not a JSON compatible type or does not include the @json flag!`); | ||
} | ||
for (const member of schema.members) { | ||
const invalidType = checkType(schema, schemas, member.node.type as NamedTypeNode, member, scopeTypes, schema.name); | ||
if (invalidType) logError(`Type ${invalidType.type} in ${invalidType.path} does not implement a JSON compatible type!\n${chalk.dim(` at ${member.node.range.source.normalizedPath.replace("~lib/", "./node_modules/")}`)}`); | ||
} | ||
return null; | ||
} | ||
function checkType( | ||
schema: SchemaData, | ||
schemas: SchemaData[], | ||
typ: NamedTypeNode, | ||
member: Property, | ||
scopeTypes: Set<string>, | ||
path: string, | ||
): { | ||
type: string; | ||
path: string; | ||
} | null { | ||
path += "." + member.name; | ||
if (schemas.find(v => v.node.name.text === typ.name.identifier.text)) scopeTypes.add(typ.name.identifier.text); | ||
if (!scopeTypes.has(typ.name.identifier.text)) return { type: toString(typ), path }; | ||
if (typ.isNullable && isPrimitive(typ)) return { type: toString(typ), path }; | ||
if (typ.typeArguments?.length && typ.typeArguments?.length > 0) { | ||
for (const ty of typ.typeArguments.filter((v) => v instanceof NamedTypeNode)) { | ||
const check = checkType(schema, schemas, ty, member, scopeTypes, path); | ||
if (check) return { type: toString(typ), path }; | ||
} | ||
} else { | ||
if (scopeTypes.has(typ.name.identifier.text)) return null; | ||
} | ||
return null; | ||
} | ||
function logError(message: string): never { | ||
console.log("\n" + chalk.bold.bgRed(" Error ") + chalk.dim(":") + " " + message + "\n"); | ||
process.exit(1); | ||
} | ||
enum PropertyFlags { | ||
@@ -474,6 +497,8 @@ Null, | ||
public value: string | null = null; | ||
public flags: Map<PropertyFlags, string[]> = new Map<PropertyFlags, string[]>(); | ||
public flags: Map<PropertyFlags, string[]> = new Map< | ||
PropertyFlags, | ||
string[] | ||
>(); | ||
public serialize: string | null = null; | ||
public serialize_pretty: string | null = null; | ||
public deserialize: string | null = null; | ||
@@ -495,3 +520,3 @@ public initialize: string | null = null; | ||
if (this.flags.has(PropertyFlags.Null)) { | ||
this.right_s = "(this." + name + ' || "null")'; | ||
this.right_s = "(this." + name + " || \"null\")"; | ||
this.right_d = "value_start === value_end - 4 && 30399761348886638 === load<u64>(changetype<usize>(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)"; | ||
@@ -504,3 +529,4 @@ } else { | ||
this.right_s = "__SERIALIZE<" + type + ">(this." + name + ")"; | ||
this.right_d = "__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
this.right_d = | ||
"__DESERIALIZE<" + type + ">(data.substring(value_start, value_end))"; | ||
} | ||
@@ -510,13 +536,28 @@ | ||
const condition = this.flags.get(PropertyFlags.OmitIf)![0]; | ||
if (!condition) throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition"); | ||
this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${" + condition + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
if (!condition) | ||
throw new Error( | ||
"Could not find condition when using decorator @omitif! Provide at least one condition", | ||
); | ||
this.serialize = | ||
"${" + | ||
condition + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
} else if (this.flags.has(PropertyFlags.OmitNull)) { | ||
this.serialize = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; | ||
this.serialize_pretty = "${changetype<usize>(this." + name + ") == <usize>0" + ' ? "" : \'' + escapedName + ": ' + " + this.right_s + ' + ","}'; | ||
this.serialize = | ||
"${changetype<usize>(this." + | ||
name + | ||
") == <usize>0" + | ||
' ? "" : \'' + | ||
escapedName + | ||
":' + " + | ||
this.right_s + | ||
' + ","}'; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
} else { | ||
this.serialize = escapedName + ":${" + this.right_s + "}"; | ||
this.serialize_pretty = escapedName + ": ${" + this.right_s + "}"; | ||
this.deserialize = "this." + name + " = " + this.right_d + ";"; | ||
@@ -540,3 +581,5 @@ } | ||
if (offset + 3 >= data.length) { | ||
throw new Error("The string must have at least 4 characters from the specified offset."); | ||
throw new Error( | ||
"The string must have at least 4 characters from the specified offset.", | ||
); | ||
} | ||
@@ -549,3 +592,7 @@ | ||
const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode; | ||
const u64Value = | ||
(fourthCharCode << 48n) | | ||
(thirdCharCode << 32n) | | ||
(secondCharCode << 16n) | | ||
firstCharCode; | ||
@@ -594,7 +641,1 @@ return u64Value; | ||
} | ||
function isPrimitive(type: NamedTypeNode): boolean { | ||
const primitives = new Set(["u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "f32", "f64", "bool", "boolean"]); | ||
return primitives.has(type.name.identifier.text); | ||
} |
Sorry, the diff of this file is not supported yet
4335
183311
3
+ Added@assemblyscript/wasi-shim@0.1.0(transitive)
+ Added@hypermode/modus-sdk-as@0.13.5(transitive)
+ Addedjson-as@0.9.29(transitive)
+ Addedsemver@7.6.3(transitive)
+ Addedxid-ts@1.1.4(transitive)