# devalue Like `JSON.stringify`, but handles - cyclical references (`obj.self = obj`) - repeated references (`[value, value]`) - `undefined`, `Infinity`, `NaN`, `-0` - regular expressions - dates - `Map` and `Set` - `BigInt` - `ArrayBuffer` and Typed Arrays - `URL` and `URLSearchParams` - `Temporal` - custom types via replacers, reducers and revivers - promises (via `stringifyAsync`) Try it out [here](https://svelte.dev/repl/138d70def7a748ce9eda736ef1c71239?version=3.49.0). ## Goals: - Performance - Security (see [XSS mitigation](#xss-mitigation)) - Compact output ## Non-goals: - Human-readable output - Stringifying functions - Stability of serialization mechanisms between versions (i.e. if you `devalue.stringify` with one version and `devalue.parse` with another, things may break) ## Usage There are two ways to use `devalue`: ### `uneval` This function takes a JavaScript value and returns the JavaScript code to create an equivalent value — sort of like `eval` in reverse: ```js import * as devalue from 'devalue'; let obj = { message: 'hello' }; devalue.uneval(obj); // '{message:"hello"}' obj.self = obj; devalue.uneval(obj); // '(function(){let a={};a.message="hello";a.self=a;return a}())' ``` Use `uneval` when you want the most compact possible output and don't want to include any code for parsing the serialized value. The result is suitable for embedding in a ``; ``` Which would result in this: ```html ``` Using `uneval` or `stringify`, we're protected against that attack: ```js const template = ` `; ``` ```html ``` This, along with the fact that `uneval` and `stringify` bail on functions and non-POJOs, stops attackers from executing arbitrary code. Strings generated by `uneval` can be safely deserialized with `eval` or `new Function`: ```js const value = (0, eval)('(' + str + ')'); ``` ## Other security considerations While `uneval` prevents the XSS vulnerability shown above, meaning you can use it to send data from server to client, **you should not send user data from client to server** using the same method. Since it has to be evaluated, an attacker that successfully submitted data that bypassed `uneval` would have access to your system. When using `eval`, ensure that you call it _indirectly_ so that the evaluated code doesn't have access to the surrounding scope: ```js { const sensitiveData = 'Setec Astronomy'; eval('sendToEvilServer(sensitiveData)'); // pwned :( (0, eval)('sendToEvilServer(sensitiveData)'); // nice try, evildoer! } ``` Using `new Function(code)` is akin to using indirect eval. ## See also - [lave](https://github.com/jed/lave) by Jed Schmidt - [arson](https://github.com/benjamn/arson) by Ben Newman. The `stringify`/`parse` approach in `devalue` was inspired by `arson` - [oson](https://github.com/KnorpelSenf/oson) by Steffen Trog - [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte - [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo - [jsesc](https://github.com/mathiasbynens/jsesc) by Mathias Bynens - [superjson](https://github.com/blitz-js/superjson) by Blitz - [next-json](https://github.com/iccicci/next-json) by Daniele Ricci ## License [MIT](LICENSE)