# 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)