{"id":21905789,"url":"https://github.com/deno911/serialize","last_synced_at":"2025-04-15T23:49:16.423Z","repository":{"id":63802348,"uuid":"570785780","full_name":"deno911/serialize","owner":"deno911","description":"🦕 Serialize JS/TS without losing support for Date, BigInt, RegExp, Map, and much more.","archived":false,"fork":false,"pushed_at":"2022-12-25T11:24:23.000Z","size":82,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T02:51:30.134Z","etag":null,"topics":["bigint","date","deno","json-superset","map","regexp","serialize","serialize-typescript","set","structured-data","symbol"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/deno911.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-11-26T05:41:05.000Z","updated_at":"2023-09-24T20:27:55.000Z","dependencies_parsed_at":"2023-01-30T22:01:12.729Z","dependency_job_id":null,"html_url":"https://github.com/deno911/serialize","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deno911%2Fserialize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deno911%2Fserialize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deno911%2Fserialize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deno911%2Fserialize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deno911","download_url":"https://codeload.github.com/deno911/serialize/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249173061,"owners_count":21224481,"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":["bigint","date","deno","json-superset","map","regexp","serialize","serialize-typescript","set","structured-data","symbol"],"created_at":"2024-11-28T16:37:27.921Z","updated_at":"2025-04-15T23:49:16.406Z","avatar_url":"https://github.com/deno911.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 🦕 serialize\n\n##### Serialize JS/TS to a **_superset_ of JSON** without sacrificing critical data.\n\n\u003c/div\u003e\n\n## Usage\n\n### `serialize`\n\nThe string returned from the `serialize` function is **literal** and **valid** JavaScript, which can be saved to a `.js` or `.ts` file, or even embedded inside of a `\u003cscript\u003e` tag.\n\n#### [deno.land](https://deno.land/x/serialize)\n\n```ts\nimport { serialize } from \"https://deno.land/x/serialize@1.1.0/mod.ts\";\n```\n\n#### [nest.land](https://x.nest.land/gallery/serialize)\n\n```ts\nimport { serialize } from \"https://x.nest.land/serialize@1.1.0/mod.ts\";\n```\n\n### \"Kitchen Sink\" Demo\n\n```ts\nserialize({\n  strings: \"string\",\n  booleans: true,\n  numeric: 0,\n  bigint1: 10n,\n  bigint2: BigInt(10),\n  regexp1: /([^\\s]+)/g,\n  regexp2: new RegExp(\"([^\\\\s]+)\", \"g\"),\n  objects: { foo: \"foo\" },\n  arrayLikes: [1, 2, 3],\n  actualNull: null,\n  undefineds: undefined,\n  nonFinites: Number.POSITIVE_INFINITY,\n  dateObject: new Date(\"2022-11-26T05:48:02.806Z\"),\n  mapObjects: new Map([[\"hello\", \"world\"]]),\n  setObjects: new Set([123, 456]),\n  arrowFuncs: (arg) =\u003e `\"${arg}\"`,\n  globalSyms: Symbol.for(\"Deno.customInspect\"),\n});\n```\n\nThe above will produce the following string output:\n\n```ts\n'{\"strings\":\"string\",\"booleans\":true,\"numeric\":0,\"bigint1\":BigInt(\"10\"),\"bigint2\":BigInt(\"10\"),\"regexp1\":new RegExp(\"([^\\\\\\\\s]+)\", \"g\"),\"regexp2\":new RegExp(\"([^\\\\\\\\s]+)\", \"g\"),\"objects\":{\"foo\":\"foo\"},\"arrayLikes\":[1,2,3],\"actualNull\":null,\"undefineds\":undefined,\"nonFinites\":Infinity,\"dateObject\":new Date(\"2022-11-26T05:48:02.806Z\"),\"mapObjects\":new Map([[\"hello\",\"world\"]]),\"setObjects\":new Set([123,456]),\"arrowFuncs\":(arg)=\u003e`\"${arg}\"`,\"globalSyms\":Symbol.for(\"Deno.customInspect\")}';\n```\n\n\u003e **Note**: to produced a beautified string, you can pass an optional second argument to `serialize()` to define the number of spaces to be used for the indentation.\n\n---\n\n## Supported Types\n\n- [x] `Array`\n- [x] `Date`\n- [x] `Map`\n- [x] `Set`\n- [x] `URL`\n- [x] `Infinity`\n- [x] `undefined`\n- [x] `RegExp` · [`options.literalRegExp`](#optionsliteralregexp) for literal output\n- [x] `BigInt` · [`options.literalBigInt`](#optionsliteralbigint) for literal output\n- [x] `Function` · [`options.includeFunction`](#optionsincludefunction)(enabled by default)\n- [x] `Getters` · [`options.includeGetters`](#optionsincludegetters) required\n- [ ] `Symbol` · [`options.includeSymbols`](#optionsincludesymbols) required 🚧\n\n[🚧 \u003cu\u003e **More information on Symbols and Serialization**\u003c/u\u003e](#optionsincludesymbols)\n\n---\n\n## Options\n\nThe `serialize()` function accepts an `options` object for a second argument, allowing fine-grained control of various aspects of the program's behavior.\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e\u003cu\u003e\u003ccode\u003eTypeScript interface\u003c/code\u003e\u003c/u\u003e\u003c/strong\u003e\u003c/summary\u003e\u003cbr\u003e\n\n```ts\ninterface SerializeOptions {\n  /**\n   * Serialize Arrays using the `Array.from` method, which may not be available\n   * in all target environments (looking at you, Internet Explorer). Default\n   * behavior is to use the `Array.prototype.splice` method, constructing an\n   * Array from an Array-like object.\n   * @default true\n   */\n  arrayFrom?: boolean;\n\n  /**\n   * Enable serializing of any functions encountered in the target object.\n   * @default true\n   */\n  includeFunction?: boolean;\n\n  /**\n   * Serialize get property accessors (\"getters\") into their resolved values.\n   * @default false\n   */\n  includeGetters?: boolean;\n\n  /**\n   * Serialize all properties, including any that are non-enumerable (hidden).\n   * By default this is disabled, meaning that only enumerable properties are\n   * serialized and included in the output.\n   * @default false\n   */\n  includeHidden?: boolean;\n\n  /**\n   * Include `Symbol` primitives (typeof `symbol`) in the serialized output.\n   * @default true\n   */\n  includeSymbols?: boolean;\n\n  /**\n   * Skips the replacement step, treating the input as pure JSON. This means\n   * much faster processing times, at the cost of **no support** for objects\n   * like RegExp/URL/Function/etc. `**You should probably leave this alone.**\n   * @default false\n   */\n  isJSON?: boolean;\n\n  /**\n   * Serialize BigInt as literals.\n   * @example BigInt(\"100\") -\u003e 100n\n   * @default false\n   */\n  literalBigInt?: boolean;\n\n  /**\n   * Serialize RegExp as literals.\n   * @example RegExp('(a|b|c)', 'g') -\u003e /(a|b|c)/g\n   * @default false\n   */\n  literalRegExp?: boolean;\n\n  /**\n   * Attempt to silently handle raised exceptions, rather than throwing hard\n   * exceptions, by skipping over problem areas wherever possible. This is\n   * ignored if a fatal error is thrown.\n   * @default true\n   */\n  silent?: boolean;\n\n  /**\n   * Control the indentation width in the generated string.\n   * Set to 0 to disable pretty-printing entirely.\n   * @default 0\n   */\n  space?: string | number;\n\n  /**\n   * Sort entries of keyed collections (Array, Object, Set, Map).\n   * @default false\n   */\n  sorted?: boolean;\n\n  /**\n   * Custom comparator to sort entries (implies {@linkcode sorted} is `true`).\n   * **Note**: if {@linkcode sorted} is `false`, but this option is defined\n   * with a valid comparator function, it will override the former and sort\n   * all entries.\n   * @default undefined\n   */\n  sortCompareFn?: ((a: unknown, b: unknown) =\u003e number) | null;\n\n  /**\n   * The maximum length of a string before it is truncated with an ellipsis.\n   * @default undefined (no limit)\n   */\n  strAbbreviateSize?: number;\n\n  /**\n   * Skips sanitization of unsafe HTML characters.\n   * @default false\n   */\n  unsafe?: boolean;\n}\n```\n\n\u003c/details\u003e\n\n### `options.arrayFrom`\n\nSerialize Arrays using the `Array.from` method, which may not be available in all target environments.\n\nDefault behavior is to use the `Array.prototype.splice` method, constructing an Array from an Array-like object.\n\n\u003e Default value is `false`\n\n### `options.isJSON`\n\nThis option indicates the target object does not contain any functions or RegExp expressions. This enables a hot-path that allows serialization to be over 3x faster. If you're serializing a lot of data, and know its pure JSON, then you can enable this option for a speed-up.\n\n\u003e Default value is `false`\n\n```ts\nserialize(obj, { isJSON: true });\n```\n\n\u003e **Note**: still escaped for XSS prevention ([see `options.unsafe`](#optionsunsafe))\n\n### `options.includeFunction`\n\nDisable this option to **ignore** JavaScript/TypeScript functions, treating them just like `JSON.stringify` (e.g. ignore them entirely). Other features will work as expected.\n\n\u003e Default value is `true`\n\n```ts\nserialize(obj, { ignoreFunction: true });\n```\n\n### `options.includeGetters`\n\nEnable to include the source for `getter` accessor properties, which allow for computed values. If not enabled, their values will be calculated at the time of serialization\nand fixed to whatever the static output was at that point in time.\n\n\u003e Default value is `false`\n\n```ts\nconst obj = {\n  name: \"Nick\",\n  title: \"dev\",\n  get greet() {\n    return `Hello, I'm a ${this.title} named ${this.name}!`;\n  },\n};\n\nserialize(obj);\n// {\"name\":\"Nick\",\"title\":\"dev\",\"greet\":\"Hello, I'm a dev named Nick!\"}\n\nserialize(obj, { includeGetters: true });\n// {\n//   \"name\": \"Nick\",\n//   \"title\": \"dev\",\n//   get greet () {\n//     return `Hello, I'm a ${this.title} named ${this.name}!`;\n//   }\n// }\n```\n\n### `options.includeHidden`\n\nSerialize non-enumerable properties that are normally hidden.\n\n\u003e **Note**: only partially implemented\n\n\u003e Default value is `false`\n\n### `options.includeSymbols`\n\n\u003e ⚠️ **support for symbols is experimental**\n\nSerialize values with the type of `symbol`. Only works with global symbols created with the `Symbol.for()` method. Any standard symbols will be coerced into globals,\ncarrying over their description text (if any).\n\nSerializing the symbol primitive is a totally bonkers concept, and - by design - is impossible to truly achieve. In reality, it's just copying the string key from\na given symbol, and therefore there is a strong chance the one created during\nthe deserializing process **will be a different value entirely**.\n\n\u003e Default value is `true`\n\n### `options.literalBigInt`\n\nSerialize BigInt expressions into literals, e.g. `100n` rather than the default `BigInt(\"100\")`.\n\n```ts\nserialize({ big: BigInt(\"100\") }, { literalBigInt: true });\n// '{\"big\":100n}'\n```\n\n\u003e Default value is `false`, with behavior as seen below.\n\n```ts\nserialize({ bigger: 200n });\n// '{\"bigger\":BigInt(\"200\")}'\n```\n\n### `options.literalRegExp`\n\nSerialize Regular Expressions into literals, e.g. `/.../i` rather than the default `RegExp(\"...\", \"i\")`.\n\n```ts\nserialize({ pattern: /(foo|bar|baz)/i }, { literalRegExp: true });\n// '{\"pattern\":/(foo|bar|baz)/i}'\n```\n\n\u003e Default value is `false`, with behavior as seen below.\n\n```ts\nserialize({ pattern: /(foo|bar|baz)/i });\n// '{\"pattern\":new RegExp(\"(foo|bar|baz)\",\"i\")}'\n```\n\n### `options.silent`\n\nAttempt to silence most errors and diagnostic messages.\n\n\u003e Default value is `true`\n\n### `options.sorted`\n\nSort entries of keyed collections (Array, Object, Set, Map).\n\n\u003e Default value is `false`\n\n### `options.sortCompareFn`\n\nCustom comparator to sort entries in Arrays, Maps, Sets, etc.\n\n**Note**: Implies `options.sorted`. If `sorted` is `false` while this option is defined with a valid\ncomparator function, it will override the former.\n\n\u003e Default value is `undefined`\n\n### `options.space`\n\nThis option is the same as the `space` argument that can be passed to [`JSON.stringify`][JSON.stringify]. It can be used to add whitespace and indentation to the serialized output to make it more readable.\n\n\u003e Default value is `0`\n\n```ts\nserialize(obj, { space: 2 });\n```\n\n### `options.strAbbreviateSize`\n\n\u003e **Note**: not yet implemented\n\nThe maximum length of a string before it is truncated with an ellipsis.\n\n\u003e Default value is `undefined` (no limit)\n\n### `options.unsafe`\n\nThis option is to signal `serialize()` that we want to do a straight conversion, without the XSS protection. This option needs to be explicitly set to `true`. HTML characters and JavaScript line terminators will not be escaped. You will have to roll your own.\n\n\u003e Default value is `false`\n\n```ts\nserialize(obj, { unsafe: true });\n```\n\n\u003e **Note**: [please see the **Auto-Escaped Characters** section below](#auto-escaped-characters).\n\n---\n\n### Auto-Escaped Characters\n\nOne of the primary features of this module is to serialize code to a string of literal JavaScript, which can be safely embedded in an HTML document as the content of a `\u003cscript\u003e` element.\n\nIn order to make this safe, HTML entities and JS line terminators are auto-escaped:\n\n```ts\nconst dangerous = { haxorXSS: \"\u003c/script\u003e\" };\n```\n\nThe above will produce the following string, HTML-escaped output which is\nsafe to put into an HTML document as it will not cause the inline script\nelement to terminate:\n\n```ts\nserialize(dangerous);\n\n// HTML entities have been safely escaped:\n'{\"haxorXSS\":\"\\\\u003C\\\\u002Fscript\\\\u003E\"}';\n```\n\nYou can pass `unsafe` argument to `serialize()` for straight serialization:\n\n```ts\nserialize(dangerous, { unsafe: true });\n\n// HTML entities have NOT been escaped:\n'{\"haxorXSS\":\"\u003c/script\u003e\"}';\n```\n\n---\n\n## Deserializing\n\nFor some use cases you might also need to **_deserialize_** the string.\n~~This is explicitly not part of this module. However, you can easily write it yourself:~~\n\nThis is **extremely unsafe**, should probably be avoided, and is quite possibly\nunsupported by your environment. To understand why these risks exist, take a\nlook at the code behind the deserialize function:\n\n```ts\nfunction deserialize\u003cT\u003e(serialized: string): T {\n  return eval(`(${serialized})`) as T;\n}\n```\n\n\u003e **Warning**: Don't forget to wrap the **entire** serialized string with parentheses, as seen as `(` `)` in the example above). Otherwise the opening bracket `{` will be considered to be the start of a body.\n\n### Type Safety\n\n```ts\nimport {\n  deserialize,\n  serialize,\n} from \"https://deno.land/x/serialize@1.1.0/mod.ts\";\n\ninterface User {\n  name: string;\n  age: bigint;\n}\n\n// encoded to a plain old string\nconst encoded = serialize\u003cUser\u003e({ name: \"Nick\", age: 29n });\n\n// ensures the decoded data has a consistent type, and\n// instructs our IDE which properties and types to anticipate.\nconst decoded = deserialize\u003cUser\u003e(encoded);\n// =\u003e { name: string; age: bigint; }\n```\n\n---\n\n## Contributing\n\n\u003e This section assumes you have [**the GitHub CLI**][gh-cli].\n\n\u003cdetails\u003e\u003csummary\u003e\u003cstrong\u003e  ⚠️ Fixing a bug? Create an issue \u003ci\u003efirst\u003c/i\u003e!\u003c/strong\u003e\u003c/summary\u003e\u003cbr\u003e\n\nUnless, of course, you're fixing a bug for which an issue already exists!\n\nThis allows the issue to be connected to your Pull Request, creating a permanent\nrecord of your contribution to the project. It also makes it easier for\nmaintainers to track project progression.\n\nCreating an issue also ensures you're given proper credit for fixing that bug 😉\n\n\u003c/details\u003e\n\n### Fork the repository\n\n```sh\ngh repo fork deno911/serialize --clone\n```\n\n### Create a feature branch\n\n```sh\ngit checkout -b fix/typo-in-readme\n```\n\n### Make some improvements\n\nDon't forget to **format**, **lint**, and **test** your code before committing!\n\n```sh\n# hack hack hack...\n\ndeno fmt\ndeno lint --unstable\ndeno test --unstable -A --no-check\n```\n\n### Commit your changes\n\nPlease try keep all changes concise and relevant to each other.\n\n```sh\ngit add .\n\n# all commits should be signed + verified with GPG/SSH\ngit commit -S -m \"fix: typos in README.md\"\n\ngit push\n```\n\n### Open a Pull Request\n\n```sh\ngh pr create --title \"fix: typos in README.md\"\n```\n\n**Or just open your repo on GitHub.com and follow the prompts.**\n\n\u003cdetails\u003e\u003csummary\u003eAs a general rule: \u003cstrong\u003e\u003cem\u003ethe smaller the PR, the better\u003c/em\u003e. Why?\u003c/strong\u003e\u003c/summary\u003e\u003cbr\u003e\n\n1. Implementing / reverting the effects of a small pull is easy.\n2. Large pulls can quickly become unmanageable and fragile.\n3. Large pulls make it quite difficult to identify, isolate, and fix bugs.\n\n\u003c/details\u003e\n\n\u003e **Warning**: make sure you select the upstream repo for your PR!\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n### [🅓🅔🅝🅞⑨①①][deno911]\n\n##### Written in TypeScript, for Deno and the Web.\n\n###### Inspired by the [serialize-javascript][sjs-gh] project by Yahoo! Inc.\n\n\u003c/div\u003e\n\n[JSON.stringify]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify\n[deno911]: https://github.com/deno911\n[gh-cli]: https://cli.github.com\n[nberlette]: https://github.com/nberlette\n[LICENSE]: https://github.com/deno911/serialize/blob/main/LICENSE\n[sjs-gh]: https://github.com/yahoo/serialize-javascript\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeno911%2Fserialize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeno911%2Fserialize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeno911%2Fserialize/lists"}