1 | # destr
|
2 |
|
3 | [![npm version][npm-version-src]][npm-version-href]
|
4 | [![npm downloads][npm-downloads-src]][npm-downloads-href]
|
5 | [![bundle][bundle-src]][bundle-href]
|
6 | [![License][license-src]][license-href]
|
7 |
|
8 | A faster, secure and convenient alternative for [`JSON.parse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).
|
9 |
|
10 | ## Usage
|
11 |
|
12 | ### Node.js
|
13 |
|
14 | Install dependency:
|
15 |
|
16 | ```bash
|
17 | # npm
|
18 | npm i destr
|
19 |
|
20 | # yarn
|
21 | yarn add destr
|
22 |
|
23 | # pnpm
|
24 | pnpm i destr
|
25 | ```
|
26 |
|
27 | Import into your Node.js project:
|
28 |
|
29 | ```js
|
30 | // ESM
|
31 | import { destr, safeDestr } from "destr";
|
32 |
|
33 | // CommonJS
|
34 | const { destr, safeDestr } = require("destr");
|
35 | ```
|
36 |
|
37 | ### Deno
|
38 |
|
39 | ```js
|
40 | import { destr, safeDestr } from "https://deno.land/x/destr/src/index.ts";
|
41 |
|
42 | console.log(destr('{ "deno": "yay" }'));
|
43 | ```
|
44 |
|
45 | ## Why?
|
46 |
|
47 | ### ✅ Type Safe
|
48 |
|
49 | ```ts
|
50 | const obj = JSON.parse("{}"); // obj type is any
|
51 |
|
52 | const obj = destr("{}"); // obj type is unknown by default
|
53 |
|
54 | const obj = destr<MyInterface>("{}"); // obj is well-typed
|
55 | ```
|
56 |
|
57 | ### ✅ Fast fallback to input if is not string
|
58 |
|
59 | > 🚀 Up to 500 faster than `JSON.parse`!
|
60 |
|
61 | ```js
|
62 | // Uncaught SyntaxError: Unexpected token u in JSON at position 0
|
63 | JSON.parse();
|
64 |
|
65 | // undefined
|
66 | destr();
|
67 | ```
|
68 |
|
69 | ### ✅ Fast lookup for known string values
|
70 |
|
71 | > 🚀 Up to 900 times faster than `JSON.parse`!
|
72 |
|
73 | ```js
|
74 | // Uncaught SyntaxError: Unexpected token T in JSON at position 0
|
75 | JSON.parse("TRUE");
|
76 |
|
77 | // true
|
78 | destr("TRUE");
|
79 | ```
|
80 |
|
81 | ### ✅ Fallback to original value if parse fails (empty or any plain string)
|
82 |
|
83 | > 🚀 Up to 900 times faster than `JSON.parse`!
|
84 |
|
85 | ```js
|
86 | // Uncaught SyntaxError: Unexpected token s in JSON at position 0
|
87 | JSON.parse("salam");
|
88 |
|
89 | // "salam"
|
90 | destr("salam");
|
91 | ```
|
92 |
|
93 | **Note:** This fails in safe/strict mode with `safeDestr`.
|
94 |
|
95 | ### ✅ Avoid prototype pollution
|
96 |
|
97 | ```js
|
98 | const input = '{ "user": { "__proto__": { "isAdmin": true } } }';
|
99 |
|
100 | // { user: { __proto__: { isAdmin: true } } }
|
101 | JSON.parse(input);
|
102 |
|
103 | // { user: {} }
|
104 | destr(input);
|
105 | ```
|
106 |
|
107 | ### ✅ Strict Mode
|
108 |
|
109 | When using `safeDestr` it will throw an error if the input is not a valid JSON string or parsing fails. (non string values and built-ins will be still returned as-is)
|
110 |
|
111 | ```js
|
112 | // Returns "[foo"
|
113 | destr("[foo");
|
114 |
|
115 | // Throws an error
|
116 | safeDestr("[foo");
|
117 | ```
|
118 |
|
119 | ## Benchmarks
|
120 |
|
121 | Locally try with `pnpm benchmark`. Below are esults on Node.js **v18.16.0** with MBA M2.
|
122 |
|
123 | **Note** `destr` is sometimes little bit slower than `JSON.parse` when parsing a valid JSON string mainly because of transform to avoid [prototype pollution](https://learn.snyk.io/lessons/prototype-pollution/javascript/) which can lead to serious security issues if not being sanitized. In the other words, `destr` is better when input is not always a json string or from untrusted source like request body.
|
124 |
|
125 | ```
|
126 | === Non-string fallback ==
|
127 | JSON.parse x 9,498,532 ops/sec ±0.57% (96 runs sampled)
|
128 | destr x 153,323,211 ops/sec ±0.13% (99 runs sampled)
|
129 | safeDestr x 64,237,062 ops/sec ±0.22% (96 runs sampled)
|
130 | sjson:
|
131 | @hapi/bourne x 9,190,459 ops/sec ±0.50% (93 runs sampled)
|
132 | Fastest is destr
|
133 |
|
134 | === Known values ==
|
135 | JSON.parse x 14,260,909 ops/sec ±0.54% (95 runs sampled)
|
136 | destr x 72,916,945 ops/sec ±0.15% (98 runs sampled)
|
137 | safeDestr x 36,544,906 ops/sec ±0.31% (98 runs sampled)
|
138 | sjson x 11,157,730 ops/sec ±0.53% (96 runs sampled)
|
139 | @hapi/bourne x 13,241,853 ops/sec ±0.73% (93 runs sampled)
|
140 | Fastest is destr
|
141 |
|
142 | === plain string ==
|
143 | JSON.parse (try-catch) x 10,603,912 ops/sec ±0.75% (91 runs sampled)
|
144 | destr x 82,123,481 ops/sec ±2.37% (99 runs sampled)
|
145 | safeDestr x 40,737,935 ops/sec ±0.97% (96 runs sampled)
|
146 | sjson (try-catch) x 9,194,305 ops/sec ±1.96% (94 runs sampled)
|
147 | @hapi/bourne x 10,816,232 ops/sec ±1.59% (90 runs sampled)
|
148 | Fastest is destr
|
149 |
|
150 | === package.json ==
|
151 | JSON.parse x 403,428 ops/sec ±0.31% (101 runs sampled)
|
152 | destr x 338,668 ops/sec ±0.27% (97 runs sampled)
|
153 | safeDestr x 335,756 ops/sec ±0.29% (98 runs sampled)
|
154 | sjson x 355,493 ops/sec ±0.15% (101 runs sampled)
|
155 | @hapi/bourne x 384,948 ops/sec ±0.24% (98 runs sampled)
|
156 | Fastest is JSON.parse
|
157 |
|
158 | === broken object ==
|
159 | JSON.parse (try-catch) x 406,262 ops/sec ±0.18% (100 runs sampled)
|
160 | destr x 337,602 ops/sec ±0.37% (99 runs sampled)
|
161 | safeDestr x 320,071 ops/sec ±0.35% (97 runs sampled)
|
162 | sjson (try-catch) x 326,689 ops/sec ±0.41% (97 runs sampled)
|
163 | @hapi/bourne x 313,024 ops/sec ±0.91% (94 runs sampled)
|
164 | Fastest is JSON.parse (try-catch)
|
165 | ```
|
166 |
|
167 | ## License
|
168 |
|
169 | MIT. Made with 💖
|
170 |
|
171 |
|
172 |
|
173 | [npm-version-src]: https://img.shields.io/npm/v/destr?style=flat&colorA=18181B&colorB=F0DB4F
|
174 | [npm-version-href]: https://npmjs.com/package/destr
|
175 | [npm-downloads-src]: https://img.shields.io/npm/dm/destr?style=flat&colorA=18181B&colorB=F0DB4F
|
176 | [npm-downloads-href]: https://npmjs.com/package/destr
|
177 | [bundle-src]: https://img.shields.io/bundlephobia/minzip/destr?style=flat&colorA=18181B&colorB=F0DB4F
|
178 | [bundle-href]: https://bundlephobia.com/result?p=destr
|
179 | [license-src]: https://img.shields.io/github/license/unjs/destr.svg?style=flat&colorA=18181B&colorB=F0DB4F
|
180 | [license-href]: https://github.com/unjs/destr/blob/main/LICENSE
|