{"id":13726914,"url":"https://github.com/JairusSW/json-as","last_synced_at":"2025-05-07T22:30:37.593Z","repository":{"id":41941719,"uuid":"367114054","full_name":"JairusSW/json-as","owner":"JairusSW","description":"The only JSON library you'll need for AssemblyScript. SIMD enabled","archived":false,"fork":false,"pushed_at":"2025-04-07T05:31:42.000Z","size":3604,"stargazers_count":93,"open_issues_count":4,"forks_count":15,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-29T02:56:09.287Z","etag":null,"topics":["assemblyscript","json","parse","performance","serialize","speed","stringify"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JairusSW.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["JairusSW"]}},"created_at":"2021-05-13T16:47:41.000Z","updated_at":"2025-04-12T13:59:07.000Z","dependencies_parsed_at":"2022-08-27T05:00:20.171Z","dependency_job_id":"93a1da9c-82a9-4aed-b58b-db1974d6b56d","html_url":"https://github.com/JairusSW/json-as","commit_stats":{"total_commits":558,"total_committers":10,"mean_commits":55.8,"dds":"0.11111111111111116","last_synced_commit":"67dcfb539d1b821ea9cc6e45ed4acd1ae0e55efe"},"previous_names":["aspkg/as-json","jairussw/json-as","jairussw/as-json"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JairusSW%2Fjson-as","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JairusSW%2Fjson-as/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JairusSW%2Fjson-as/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JairusSW%2Fjson-as/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JairusSW","download_url":"https://codeload.github.com/JairusSW/json-as/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252965099,"owners_count":21832822,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assemblyscript","json","parse","performance","serialize","speed","stringify"],"created_at":"2024-08-03T01:03:31.262Z","updated_at":"2025-05-07T22:30:37.572Z","avatar_url":"https://github.com/JairusSW.png","language":"TypeScript","readme":"\u003ch5 align=\"center\"\u003e\n  \u003cpre\u003e\n\u003cspan style=\"font-size: 0.8em;\"\u003e     ██ ███████  ██████  ███    ██        █████  ███████\n     ██ ██      ██    ██ ████   ██       ██   ██ ██     \n     ██ ███████ ██    ██ ██ ██  ██ █████ ███████ ███████\n██   ██      ██ ██    ██ ██  ██ ██       ██   ██      ██\n █████  ███████  ██████  ██   ████       ██   ██ ███████\n \u003c/span\u003e\n    AssemblyScript - v1.0.4\n  \u003c/pre\u003e\n\u003c/h5\u003e\n\n## 📝 About\n\nJSON is the de-facto serialization format of modern web applications, but its serialization and deserialization remain a significant performance bottleneck, especially at scale. Traditional parsing approaches are computationally expensive, adding unnecessary overhead to both clients and servers. This library is designed to mitigate this by leveraging SIMD acceleration and highly optimized transformations.\n\n## 🔭 What's new\n\n🔹Major performance improvements and addition of SIMD\n\n🔹Near zero-growth allocation design and low overhead\n\n🔹Support for custom serializer and deserializers\n\n🔹Fixes to many, many, bugs and edge cases\n\n🔹Support for dynamic objects, arrays, arbitrary values, and raw types\n\n## 📚 Contents\n\n- [Installation](#-installation)\n- [Usage](#-usage)\n- [Examples](#-examples)\n  - [Omitting Fields](#️-omitting-fields)\n  - [Nullable Primitives](#️-using-nullable-primitives)\n  - [Unknown or Dynamic Data](#-working-with-unknown-or-dynamic-data)\n  - [Using Raw JSON Strings](#️-using-raw-json-strings)\n  - [Custom Serializers](#️-using-custom-serializers-or-deserializers)\n- [Performance](#-performance)\n- [License](#-license)\n- [Contact](#-contact)\n\n## 💾 Installation\n\n```bash\nnpm install json-as\n```\n\nAdd the `--transform` to your `asc` command (e.g. in package.json)\n\n```bash\n--transform json-as/transform\n```\n\nAlternatively, add it to your `asconfig.json`\n\n```typescript\n{\n  \"options\": {\n    \"transform\": [\"json-as/transform\"]\n  }\n}\n```\n\nIf you'd like to see the code that the transform generates, run the build step with `DEBUG=true`\n\n## 🪄 Usage\n\n```typescript\nimport { JSON } from \"json-as\";\n\n@json\nclass Vec3 {\n  x: f32 = 0.0;\n  y: f32 = 0.0;\n  z: f32 = 0.0;\n}\n\n@json\nclass Player {\n  @alias(\"first name\")\n  firstName!: string;\n  lastName!: string;\n  lastActive!: i32[];\n  // Drop in a code block, function, or expression that evaluates to a boolean\n  @omitif((self: Player) =\u003e self.age \u003c 18)\n  age!: i32;\n  @omitnull()\n  pos!: Vec3 | null;\n  isVerified!: boolean;\n}\n\nconst player: Player = {\n  firstName: \"Jairus\",\n  lastName: \"Tanaka\",\n  lastActive: [3, 9, 2025],\n  age: 18,\n  pos: {\n    x: 3.4,\n    y: 1.2,\n    z: 8.3,\n  },\n  isVerified: true,\n}\n\nconst serialized = JSON.stringify\u003cPlayer\u003e(player);\nconst deserialized = JSON.parse\u003cPlayer\u003e(serialized);\n\nconsole.log(\"Serialized    \" + serialized);\nconsole.log(\"Deserialized  \" + JSON.stringify(deserialized));\n```\n\n## 🔍 Examples\n\n### 🏷️ Omitting Fields\n\nThis library allows selective omission of fields during serialization using the following decorators:\n\n**@omit**\n\nThis decorator excludes a field from serialization entirely.\n\n```typescript\n@json\nclass Example {\n  name!: string;\n  @omit\n  SSN!: string;\n}\n\nconst obj = new Example();\nobj.name = \"Jairus\";\nobj.SSN = \"123-45-6789\";\n\nconsole.log(JSON.stringify(obj)); // { \"name\": \"Jairus\" }\n```\n\n**@omitnull**\n\nThis decorator omits a field only if its value is null.\n\n```typescript\n@json\nclass Example {\n  name!: string;\n  @omitnull()\n  optionalField!: string | null;\n}\n\nconst obj = new Example();\nobj.name = \"Jairus\";\nobj.optionalField = null;\n\nconsole.log(JSON.stringify(obj)); // { \"name\": \"Jairus\" }\n```\n\n**@omitif((self: this) =\u003e condition)**\n\nThis decorator omits a field based on a custom predicate function.\n\n```typescript\n@json\nclass Example {\n  name!: string;\n  @omitif((self: Example) =\u003e self.age \u003c= 18)\n  age!: number;\n}\n\nconst obj = new Example();\nobj.name = \"Jairus\";\nobj.age = 18;\n\nconsole.log(JSON.stringify(obj)); // { \"name\": \"Jairus\" }\n\nobj.age = 99;\n\nconsole.log(JSON.stringify(obj)); // { \"name\": \"Jairus\", \"age\": 99 }\n```\n\nIf age were higher than 18, it would be included in the serialization.\n\n### 🗳️ Using nullable primitives\n\nAssemblyScript doesn't support using nullable primitive types, so instead, json-as offers the `JSON.Box` class to remedy it.\n\nFor example, this schema won't compile in AssemblyScript:\n\n```typescript\n@json\nclass Person {\n  name!: string;\n  age: i32 | null = null;\n}\n```\n\nInstead, use `JSON.Box` to allow nullable primitives:\n\n```typescript\n@json\nclass Person {\n  name: string;\n  age: JSON.Box\u003ci32\u003e | null = null;\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nconst person = new Person(\"Jairus\");\nconsole.log(JSON.stringify(person)); // {\"name\":\"Jairus\",\"age\":null}\n\nperson.age = new JSON.Box\u003ci32\u003e(18); // Set age to 18\nconsole.log(JSON.stringify(person)); // {\"name\":\"Jairus\",\"age\":18}\n```\n\n### 📤 Working with unknown or dynamic data\n\nSometimes it's necessary to work with unknown data or data with dynamic types.\n\nBecause AssemblyScript is a statically-typed language, that typically isn't allowed, so json-as provides the `JSON.Value` and `JSON.Obj` types.\n\nHere's a few examples:\n\n**Working with multi-type arrays**\n\nWhen dealing with arrays that have multiple types within them, eg. `[\"string\",true,[\"array\"]]`, use `JSON.Value[]`\n\n```typescript\nconst a = JSON.parse\u003cJSON.Value[]\u003e('[\"string\",true,[\"array\"]]');\nconsole.log(JSON.stringify(a[0])); // \"string\"\nconsole.log(JSON.stringify(a[1])); // true\nconsole.log(JSON.stringify(a[2])); // [\"array\"]\n```\n\n**Working with unknown objects**\n\nWhen dealing with an object with an unknown structure, use the `JSON.Obj` type\n\n```typescript\nconst obj = JSON.parse\u003cJSON.Obj\u003e('{\"a\":3.14,\"b\":true,\"c\":[1,2,3],\"d\":{\"x\":1,\"y\":2,\"z\":3}}');\n\nconsole.log(\"Keys: \" + obj.keys().join(\" \")); // a b c d\nconsole.log(\"Values: \" +\n  obj\n    .values()\n    .map\u003cstring\u003e((v) =\u003e JSON.stringify(v))\n    .join(\" \"),\n); // 3.14 true [1,2,3] {\"x\":1,\"y\":2,\"z\":3}\n\nconst y = obj.get(\"d\")!.get\u003cJSON.Obj\u003e().get(\"y\")!;\nconsole.log('o1[\"d\"][\"y\"] = ' + y.toString()); // o1[\"d\"][\"y\"] = 2\n```\n\n**Working with dynamic types within a schema**\n\nMore often, objects will be completely statically typed except for one or two values.\n\nIn such cases, `JSON.Value` can be used to handle fields that may hold different types at runtime.\n\n```typescript\n@json\nclass DynamicObj {\n  id: i32 = 0;\n  name: string = \"\";\n  data!: JSON.Value; // Can hold any type of value\n}\n\nconst obj = new DynamicObj();\nobj.id = 1;\nobj.name = \"Example\";\nobj.data = JSON.parse\u003cJSON.Value\u003e('{\"key\":\"value\"}'); // Assigning an object\n\nconsole.log(JSON.stringify(obj)); // {\"id\":1,\"name\":\"Example\",\"data\":{\"key\":\"value\"}}\n\nobj.data = JSON.Value.from\u003ci32\u003e(42); // Changing to an integer\nconsole.log(JSON.stringify(obj)); // {\"id\":1,\"name\":\"Example\",\"data\":42}\n\nobj.data = JSON.Value.from(\"a string\"); // Changing to a string\nconsole.log(JSON.stringify(obj)); // {\"id\":1,\"name\":\"Example\",\"data\":\"a string\"}\n```\n\n### 🏗️ Using Raw JSON strings\n\nSometimes its necessary to simply copy a string instead of serializing it.\n\nFor example, the following data would typically be serialized as:\n\n```typescript\nconst map = new Map\u003cstring, string\u003e();\nmap.set(\"pos\", '{\"x\":1.0,\"y\":2.0,\"z\":3.0}');\n\nconsole.log(JSON.stringify(map));\n// {\"pos\":\"{\\\"x\\\":1.0,\\\"y\\\":2.0,\\\"z\\\":3.0}\"}\n// pos's value (Vec3) is contained within a string... ideally, it should be left alone\n```\n\nIf, instead, one wanted to insert Raw JSON into an existing schema/data structure, they could make use of the JSON.Raw type to do so:\n\n```typescript\nconst map = new Map\u003cstring, JSON.Raw\u003e();\nmap.set(\"pos\", new JSON.Raw('{\"x\":1.0,\"y\":2.0,\"z\":3.0}'));\n\nconsole.log(JSON.stringify(map));\n// {\"pos\":{\"x\":1.0,\"y\":2.0,\"z\":3.0}}\n// Now its properly formatted JSON where pos's value is of type Vec3 not string!\n```\n\n### ⚒️ Using custom serializers or deserializers\n\nThis library supports custom serialization and deserialization methods, which can be defined using the `@serializer` and `@deserializer` decorators.\n\nHere's an example of creating a custom data type called `Point` which serializes to `(x,y)`\n\n```typescript\nimport { bytes } from \"json-as/assembly/util\";\n\n@json\nclass Point {\n  x: f64 = 0.0;\n  y: f64 = 0.0;\n  constructor(x: f64, y: f64) {\n    this.x = x;\n    this.y = y;\n  }\n\n  @serializer\n  serializer(self: Point): string {\n    return `(${self.x},${self.y})`;\n  }\n\n  @deserializer\n  deserializer(data: string): Point {\n    const dataSize = bytes(data);\n    if (dataSize \u003c= 2) throw new Error(\"Could not deserialize provided data as type Point\");\n\n    const c = data.indexOf(\",\");\n    const x = data.slice(1, c);\n    const y = data.slice(c + 1, data.length - 1);\n\n    return new Point(f64.parse(x), f64.parse(y));\n  }\n}\n\nconst obj = new Point(3.5, -9.2);\n\nconst serialized = JSON.stringify\u003cPoint\u003e(obj);\nconst deserialized = JSON.parse\u003cPoint\u003e(serialized);\n\nconsole.log(\"Serialized    \" + serialized);\nconsole.log(\"Deserialized  \" + JSON.stringify(deserialized));\n```\n\nThe serializer function converts a `Point` instance into a string format `(x,y)`.\n\nThe deserializer function parses the string `(x,y)` back into a `Point` instance.\n\nThese functions are then wrapped before being consumed by the json-as library:\n\n```typescript\n@inline __SERIALIZE_CUSTOM(ptr: usize): void {\n  const data = this.serializer(changetype\u003cPoint\u003e(ptr));\n  const dataSize = data.length \u003c\u003c 1;\n  memory.copy(bs.offset, changetype\u003cusize\u003e(data), dataSize);\n  bs.offset += dataSize;\n}\n\n@inline __DESERIALIZE_CUSTOM(data: string): Point {\n  return this.deserializer(data);\n}\n```\n\nThis allows custom serialization while maintaining a generic interface for the library to access.\n\n## ⚡ Performance\n\nThe `json-as` library has been optimized to achieve near-gigabyte-per-second JSON processing speeds through SIMD acceleration and highly efficient transformations. Below are detailed statistics comparing performance metrics such as build time, operations-per-second, and throughput.\n\n### 🔍 Comparison to JavaScript\n\nThese benchmarks compare this library to JavaScript's native `JSON.stringify` and `JSON.parse` functions.\n\n**Table 1** - _AssemblyScript (LLVM)_\n\n| Test Case       | Size       | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |\n| --------------- | ---------- | --------------------- | ----------------------- | -------------------- | ---------------------- |\n| Vector3 Object  | 38 bytes   | 35,714,285 ops/s      | 35,435,552 ops/s        | 1,357 MB/s           | 1,348 MB/s             |\n| Alphabet String | 104 bytes  | 13,617,021 ops/s      | 18,390,804 ops/s        | 1,416 MB/s           | 1,986 MB/s             |\n| Small Object    | 88 bytes   | 24,242,424 ops/s      | 12,307,692 ops/s        | 2,133 MB/s           | 1,083 MB/s             |\n| Medium Object   | 494 bytes  | 4,060,913 ops/s       | 1,396,160 ops/s         | 2,006 MB/s           | 689.7 MB/s             |\n| Large Object    | 3374 bytes | 614,754 ops/s         | 132,802 ops/s           | 2,074 MB/s           | 448.0 MB/s             |\n\n**Table 2** - _JavaScript (V8)_\n\n| Test Case       | Size       | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |\n| --------------- | ---------- | --------------------- | ----------------------- | -------------------- | ---------------------- |\n| Vector3 Object  | 38 bytes   | 8,791,209 ops/s       | 5,369,12 ops/s          | 357.4 MB/s           | 204.3 MB/s             |\n| Alphabet String | 104 bytes  | 13,793,103 ops/s      | 14,746,544 ops/s        | 1,416 MB/s           | 1,592 MB/s             |\n| Small Object    | 88 bytes   | 8,376,963 ops/s       | 4,968,944 ops/s         | 737.1 MB/s           | 437.2 MB/s             |\n| Medium Object   | 494 bytes  | 2,395,210 ops/s       | 1,381,693 ops/s         | 1,183 MB/s           | 682.5 MB/s             |\n| Large Object    | 3374 bytes | 222,222 ops/s         | 117,233 ops/s           | 749.7 MB/s           | 395.5 MB/s             |\n\n**📌 Insights**\n\n- JSON-AS consistently outperforms JavaScript's native implementation.\n\n- **Serialization Speed:**\n  - JSON-AS achieves speeds up to `2,133 MB/s`, significantly faster than JavaScript's peak of `1,416 MB/s`.\n  - Large objects see the biggest improvement, with JSON-AS at `2,074 MB/s` vs. JavaScript’s `749.7 MB/s`.\n\n- **Deserialization Speed:**\n  - JSON-AS reaches `1,986 MB/s`, while JavaScript caps at `1,592 MB/s`.\n  - Small and medium objects see the most significant performance boost overall.\n\n### 📈 Comparison to v0.9.x version\n\n**Table 1** - _v1.0.0_\n\n| Test Case       | Size       | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |\n| --------------- | ---------- | --------------------- | ----------------------- | -------------------- | ---------------------- |\n| Vector3 Object  | 38 bytes   | 35,714,285 ops/s      | 35,435,552 ops/s        | 1,357 MB/s           | 1,348 MB/s             |\n| Alphabet String | 104 bytes  | 13,617,021 ops/s      | 18,390,804 ops/s        | 1,416 MB/s           | 1,986 MB/s             |\n| Small Object    | 88 bytes   | 24,242,424 ops/s      | 12,307,692 ops/s        | 2,133 MB/s           | 1,083 MB/s             |\n| Medium Object   | 494 bytes  | 4,060,913 ops/s       | 1,396,160 ops/s         | 2,006 MB/s           | 689.7 MB/s             |\n| Large Object    | 3374 bytes | 614,754 ops/s         | 132,802 ops/s           | 2,074 MB/s           | 448.0 MB/s             |\n\n**Table 2** - _v0.9.29_\n\n| Test Case       | Size       | Serialization (ops/s) | Deserialization (ops/s) | Serialization (MB/s) | Deserialization (MB/s) |\n| --------------- | ---------- | --------------------- | ----------------------- | -------------------- | ---------------------- |\n| Vector3 Object  | 38 bytes   | 6,896,551 ops/s       | 10,958,904 ops/s        | 262.1 MB/s           | 416.4 MB/s             |\n| Alphabet String | 104 bytes  | 5,128,205 ops/s       | 8,695,652 ops/s         | 533.3 MB/s           | 939.1 MB/s             |\n| Small Object    | 88 bytes   | 4,953,560 ops/s       | 3,678,160 ops/s         | 435.9 MB/s           | 323.7 MB/s             |\n| Medium Object   | 494 bytes  | 522,193 ops/s         | 508,582 ops/s           | 258.0 MB/s           | 251.2 MB/s             |\n| Large Object    | 3374 bytes | 51,229 ops/s          | 65,585 ops/s            | 172.8 MB/s           | 221.3 MB/s             |\n\n**📌 Insights:**\n\n- Massive performance improvements in JSON-AS `v1.0.0`:\n- Serialization is **2-12x faster** (e.g., Large Object: `2,074 MB/s` vs. `172.8 MB/s`).\n- Deserialization is **2-3x faster** (e.g., Large Object: `1,348 MB/s` vs. `221.3 MB/s`).\n- Vector3 Object serialization improved from `416 MB/s` to `1,357 MB/s`--a **3x benefit** through new code generation techniques.\n\n## 🔭 What's Next\n\n- Theorize plans to keep key-order in generated schemas\n- Generate optimized deserialization methods\n- Inline specific hot code paths\n- Implement error handling implementation\n\n## 📃 License\n\nThis project is distributed under an open source license. You can view the full license using the following link: [License](./LICENSE)\n\n## 📫 Contact\n\nPlease send all issues to [GitHub Issues](https://github.com/JairusSW/json-as/issues) and to converse, please send me an email at [me@jairus.dev](mailto:me@jairus.dev)\n\n- **Email:** Send me inquiries, questions, or requests at [me@jairus.dev](mailto:me@jairus.dev)\n- **GitHub:** Visit the official GitHub repository [Here](https://github.com/JairusSW/json-as)\n- **Website:** Visit my official website at [jairus.dev](https://jairus.dev/)\n- **Discord:** Contact me at [My Discord](https://discord.com/users/600700584038760448) or on the [AssemblyScript Discord Server](https://discord.gg/assemblyscript/)","funding_links":["https://github.com/sponsors/JairusSW"],"categories":["Packages","TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJairusSW%2Fjson-as","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJairusSW%2Fjson-as","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJairusSW%2Fjson-as/lists"}