{"id":31589449,"url":"https://github.com/dancecoder/json22","last_synced_at":"2025-10-06T02:53:08.674Z","repository":{"id":57285503,"uuid":"446655506","full_name":"dancecoder/json22","owner":"dancecoder","description":"The JSON22 is a superset of JSON with an ability to serialize/deserialize classes and extended support for number variables","archived":false,"fork":false,"pushed_at":"2022-02-27T04:43:09.000Z","size":98,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-30T19:26:08.237Z","etag":null,"topics":["json-serialization","json22","serialization","serialization-format"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/dancecoder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-11T02:47:59.000Z","updated_at":"2022-02-16T14:20:24.000Z","dependencies_parsed_at":"2022-08-25T03:50:32.412Z","dependency_job_id":null,"html_url":"https://github.com/dancecoder/json22","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/dancecoder/json22","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dancecoder%2Fjson22","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dancecoder%2Fjson22/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dancecoder%2Fjson22/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dancecoder%2Fjson22/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dancecoder","download_url":"https://codeload.github.com/dancecoder/json22/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dancecoder%2Fjson22/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278551493,"owners_count":26005388,"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","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["json-serialization","json22","serialization","serialization-format"],"created_at":"2025-10-06T02:53:06.284Z","updated_at":"2025-10-06T02:53:08.668Z","avatar_url":"https://github.com/dancecoder.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JSON22 - JSON with types\nThe JSON22 is a superset of [JSON](https://tools.ietf.org/html/rfc7159) with an ability to serialize/deserialize \nclasses and extended support for number variables.\n\n## TL;DR\n### To there ...\n```javascript\nconst value = {\n    name: \"Femistoclus\",\n    amount: 3873133n,\n    debt: NaN,\n    date: new Date('2022-01-07'),\n};\nconst string = JSON22.stringify(value);\nconsole.log(string);\n// =\u003e\n// {\n//    \"name\": \"Femistoclus\"\n//    \"amount\": 3873133n,\n//    \"debt\": NaN,\n//    \"date\": Date(1641513600000),\n// }\n```\n\n### ... and back\n```javascript\nconst string = `{\n  \"name\": \"Femistoclus\"\n  \"amount\": 3873133n,\n  \"debt\": NaN,\n  \"date\": Date(1641513600000),\n}`;\nconst value = JSON22.parse(string);\nconsole.log(typeof value.date, value.date.constructor.name); // =\u003e object Date\nconsole.log(typeof value.amount); // =\u003e bigint\nconsole.log(typeof value.debt, isNaN(value.debt)); // =\u003e number true\n```\n\n## Features\n* Can parse standard `JSON` format\n* Support for `BigInt` values\n* Support for `NaN` values\n* Support for `Infinity`/`-Infinity` values\n* Support for typed serialization/deserialization, work with `Date` class out of the box\n* Allow using trailing commas\n* Zero-dependency npm-package\n* Both CJS/ESM modules support\n\n## Installation\n```shell\nnpm install json22\n```\nIn your code\n```javascript\nimport { JSON22 } from 'json22'\n\nconst data = { date: new Date() };\nconst s = JSON22.stringify(data);\n```\n\nFor old-fashioned applications\n```javascript\nconst { JSON22 } = require('json22'); \n\nconst data = { date: new Date() };\nconst s = JSON22.stringify(data);\n```\n\n## Integration\n### Using with Express\nThere is library [json22-express](https://github.com/dancecoder/json22-express) providing JSON22 support for expressjs applications\n```javascript\nimport express from 'express'; \nimport { json22express } from 'json22-express'\n\nconst app = express();\napp.use(json22express());\n\napp.get('/date', (req, res, next) =\u003e {\n    res.status(200).json22({ date: new Date() });\n    next();\n});\n```\n### Using with Axios\nThere is library [json22-axios](https://github.com/dancecoder/json22-axios) providing JSON22 support for client applications\n```javascript\nimport axios from 'axios';\nimport { Json22RequestInterceptor } from 'json22-axios';\n\naxios.interceptors.request.use(Json22RequestInterceptor());\n\nasync function geServerDate() {\n  try {\n      const resp = await axios.get('/date');\n      return resp.data.date;\n  } catch (e) {\n    console.error(e);\n  }\n  return null;\n}\n```\n\n## API\nNote: JSON22 cannot be used as drop in JSON object replacement due to `parse` and `stringify` methods\narguments incompatibility. But you may not be worried in case you are using first arguments only.\n```typescript\nclass JSON22 {\n    static readonly mimeType: string;\n    static parse\u003cT\u003e(text: string, options?: Json22ParseOptions): T;\n    static stringify(value: any, options?: Json22StringifyOptions): string;\n}\n\ninterface Json22ParseOptions {\n    context?: Record\u003cstring, { new (...args: any) }\u003e; // default { 'Date': Date }\n    // To be extended\n}\n\ninterface Json22StringifyOptions {\n    // To be extended\n}\n```\n\n## JSON Extensions\n\n### Numbers\n\nWith JSON22 you can use `NaN`, `Infinity`, `-Infinity` values. It means also this values will be stringified well \nin case it nested at an array or an object.\n```javascript\nJSON.stringify([42, NaN, Infinity, -Infinity]); // =\u003e [42, null, null, null] \nJSON22.stringify([42, NaN, Infinity, -Infinity]); // =\u003e [42, NaN, Infinity, -Infinity]\n```\n```javascript\nJSON.stringify({ nan: NaN }); // =\u003e { \"nan\": null } \nJSON22.stringify({ nan: NaN }); // =\u003e { \"nan\": NaN }\n```\n\n### BigInt\nJSON22 introduce support for BigInt values\n```javascript\nJSON.stringify({ bigint: 123n }); // =\u003e Uncaught TypeError: Do not know how to serialize a BigInt\nJSON22.stringify({ bigint: 123n }); // =\u003e { \"bigint\": 123n } \nJSON22.parse('{ \"bigint\": 123n }'); // =\u003e { bigint: 123n }\n```\n\n### Trailing commas\nIt was not planned, but parser implementation work well with trailing commas. \nThere is no sense to complicate the parser code to avoid it. It looks useful.\n\n```javascript\nJSON.parse('[1, 2, 3, ]'); // =\u003e Uncaught SyntaxError: Unexpected token ] in JSON at position 9\nJSON22.parse('[1, 2, 3, ]'); // =\u003e [1, 2, 3]\n```\n```javascript\nJSON.parse('{ \"a\": 1, \"b\": 2, \"c\": 3, }'); // =\u003e Uncaught SyntaxError: Unexpected token } in JSON at position 26\nJSON22.parse('{ \"a\": 1, \"b\": 2, \"c\": 3, }'); // =\u003e { a: 1, b:2, c:3 }\n```\n### Typed values\nThis is the most significant addition. It's allow you to serialize and deserialize any typed value. \nOut of the box it works well with date values.\n```javascript\nconst date = new Date('2022-01-07');\nJSON.stringify(date); // =\u003e \"2022-01-07T00:00:00.000Z\"\nJSON22.stringify(date); // =\u003e Date(1641513600000)\n```\n```javascript\nconst date = JSON22.parse('Date(1641513600000)');\nconsole.log(typeof date, date instanceof Date); // =\u003e object true \n```\nThis behavior is based on the `valueOf` method which is defined at the Object class. \nIn case JSON22 find the `valueOf` method return a value which is not equal of the object itself then it will produce\nconstructor literal. The `valueOf` of the Date class return numeric date representation. \nIf you'll call the Date constructor with that value then date will be sort of 'restored'.\n\n#### Custom valueOf implementation\nTo match this behavior you may implement you own `valueOf` method at you custom class.\n\nLet's define a model class for demonstration\n```javascript\nclass TypedModel {\n    constructor(data) {\n        this.a = data?.a;\n        this.b = data?.b;\n    }\n    valueOf() {\n        return { a: this.a, b: this.b };\n    }\n}\n```\nThat sort of classes will be serialised as typed objects\n```javascript\nconst value = new TypedModel({ a: 1, b: 2 });\nJSON22.stringify(value); // =\u003e TypedModel({ \"a\": 1, \"b\": 1 }) \n```\nThe `valueOf` methods may return any serializable values, even typed objects\n```javascript\nconst value = new TypedModel({ a: 1, b: new Date('2022-01-07') });\nJSON22.stringify(value); // =\u003e TypedModel({ \"a\": 1, \"b\": Date(1641513600000) }) \n```\n#### Parsing context\nTypically, serialization and deserialization are processes separated by different environments. \nLike serialization at a backend and deserialization at a frontend and vice versa. \nSo `TypedModel` we defined above should be shared between environments. \nAlso `JSON22` parser should have a link to this class. In theory, we can push all such classes to a global scope. \nIt is easy, however, it is not the best solution. It will produce global scope pollution, may cause naming conflicts,\nand it is not safe to allow parser to call any constructor from a global scope. That is why you should always pass\ndeserialization context to parser.\n```javascript\nconst string = 'TypedModel({ \"a\": 1, \"b\": Date(1641513600000) })';\nJSON22.parse(string); // =\u003e Error: Constructor TypedModel not defined in the context\n\nconst context = { 'TypedModel': TypedModel };\nconst value = JSON22.parse(string, { context });\nconsole.log(value instanceof TypedModel); // =\u003e true\n```\n\n#### The `valueOf` method priority\nThe JSON22 support for `toJSON` method of an object as well as JSON. In some cases an object may have both `valueOf` \nand `toJSON` methods. Typical example is the Date class. The JSON22 at first is a solution to serialize/deserialize \ndate values, so __`valueOf` have higher priority over `toJSON`__. This is also true for any object implementing `valueOf` \nand `toJSON` both. \n\n## Motivation\nJSON format is good enough for everyday usage. There are some libraries trying to introduce syntax to make JSON closer\nto modern JavaScript, some libraries trying to introduce functions serialization. All that is not important and is not\nrequired for everyday usage. However, there is one thing annoying me always - date values.\n\nWe are serializing dates a lot and each time we parse it back we are getting a string. As a result we have to deal with\nthe Date constructor manually each time. Even if we are no need date as an object, date formatter will have to make date\nobject in order to make user-friendly text representation. Otherwords we are forced to care about dates additionally.\nIt produces bulky solutions or tons of inline type conversions.\n\nBut I'm lazy developer, I'll do everything to get rid of any additional careness.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdancecoder%2Fjson22","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdancecoder%2Fjson22","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdancecoder%2Fjson22/lists"}