json-storage-formatter 3.0.2 β 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -96
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
# json-storage-formatter π
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<div align="center">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/johnny-quesada-developer/global-hooks-example/main/public/avatar2.jpeg" width="100" alt="John Avatar" />
|
|
5
|
+
|
|
6
|
+
<br />
|
|
7
|
+
<b>Type-safe serialization for any JavaScript object.<br />
|
|
8
|
+
Store and restore Maps, Sets, Dates, RegExps, Errors, and more.<br />
|
|
9
|
+
<br />
|
|
10
|
+
<i>One line. No data loss. No headaches.</i> π</b>
|
|
11
|
+
<br /><br />
|
|
12
|
+
<a href="https://www.npmjs.com/package/json-storage-formatter"><img src="https://img.shields.io/npm/v/json-storage-formatter.svg" /></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/json-storage-formatter"><img src="https://img.shields.io/npm/dm/json-storage-formatter.svg" /></a>
|
|
14
|
+
<a href="LICENSE"><img src="https://img.shields.io/npm/l/json-storage-formatter.svg" /></a>
|
|
15
|
+
</div>
|
|
4
16
|
|
|
5
|
-
|
|
17
|
+
---
|
|
6
18
|
|
|
7
|
-
##
|
|
19
|
+
## π― The Problem
|
|
8
20
|
|
|
9
21
|
```ts
|
|
10
22
|
const userProfile = {
|
|
@@ -29,35 +41,127 @@ console.log(JSON.stringify(userProfile, null, 2));
|
|
|
29
41
|
}
|
|
30
42
|
```
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
**JSON.stringify** loses all type information for Dates, Maps, Sets, RegExps, and more. Your data is flattened, and restoring it is impossible.
|
|
33
45
|
|
|
34
|
-
|
|
46
|
+
---
|
|
35
47
|
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
<div align="center">
|
|
49
|
+
<b>json-storage-formatter lets you serialize <i>any</i> JavaScript value for storage,<br />
|
|
50
|
+
and restore it to its original type β <i>automatically</i>.</b>
|
|
51
|
+
</div>
|
|
38
52
|
|
|
39
53
|
---
|
|
40
54
|
|
|
41
|
-
##
|
|
55
|
+
## π Why Use This Library?
|
|
42
56
|
|
|
43
|
-
|
|
57
|
+
## π’ Quick Start
|
|
44
58
|
|
|
45
|
-
|
|
46
|
-
2. `formatFromStore(value)` β restores it to the **exact original shape and types**.
|
|
59
|
+
### Instantly Store and Restore Complex Data
|
|
47
60
|
|
|
48
|
-
|
|
61
|
+
```ts
|
|
62
|
+
import { formatToStore, formatFromStore } from 'json-storage-formatter';
|
|
63
|
+
|
|
64
|
+
// Imagine you want to save this to localStorage, a URL, or a DB:
|
|
65
|
+
const userProfile = {
|
|
66
|
+
id: 42,
|
|
67
|
+
createdAt: new Date('2024-10-01T10:30:00Z'),
|
|
68
|
+
preferences: new Map([
|
|
69
|
+
['theme', 'dark'],
|
|
70
|
+
['languages', new Set(['en', 'es'])],
|
|
71
|
+
]),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Serialize for storage (preserves all types!)
|
|
75
|
+
const stored = formatToStore(userProfile);
|
|
76
|
+
localStorage.setItem('profile', stored);
|
|
77
|
+
|
|
78
|
+
// ...later, or in another environment:
|
|
79
|
+
const loaded = localStorage.getItem('profile');
|
|
80
|
+
const restored = formatFromStore<typeof userProfile>(loaded);
|
|
81
|
+
|
|
82
|
+
// restored.createdAt is a Date
|
|
83
|
+
// restored.preferences is a Map with a Set inside
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
// Works for any structure: deeply nested, with Dates, Sets, Maps, RegExps, Errors, undefined, NaN, etc.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## π£ Complex Types Example
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const complex = {
|
|
94
|
+
date: new Date('2024-10-01T10:30:00Z'),
|
|
95
|
+
set: new Set(['a', 'b']),
|
|
96
|
+
map: new Map([
|
|
97
|
+
['x', 1],
|
|
98
|
+
['y', 2],
|
|
99
|
+
]),
|
|
100
|
+
regex: /abc/i,
|
|
101
|
+
error: new Error('fail'),
|
|
102
|
+
undef: undefined,
|
|
103
|
+
nan: NaN,
|
|
104
|
+
inf: Infinity,
|
|
105
|
+
};
|
|
49
106
|
|
|
50
|
-
|
|
107
|
+
const stored = formatToStore(complex);
|
|
108
|
+
const restored = formatFromStore<typeof complex>(stored);
|
|
109
|
+
// All types are preserved!
|
|
110
|
+
```
|
|
51
111
|
|
|
52
112
|
---
|
|
53
113
|
|
|
54
|
-
|
|
114
|
+
### π Type-Safe Storage
|
|
55
115
|
|
|
56
|
-
|
|
116
|
+
Store and restore Maps, Sets, Dates, RegExps, Errors, and more β not just plain objects.
|
|
57
117
|
|
|
58
118
|
```ts
|
|
59
119
|
import { formatToStore, formatFromStore } from 'json-storage-formatter';
|
|
60
120
|
|
|
121
|
+
const original = new Map([
|
|
122
|
+
['created', new Date('2024-10-01T10:30:00Z')],
|
|
123
|
+
['tags', new Set(['a', 'b'])],
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
const json = formatToStore(original); // string for storage
|
|
127
|
+
const restored = formatFromStore<Map<string, unknown>>(json);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### β‘ No Boilerplate
|
|
131
|
+
|
|
132
|
+
Just call `formatToStore` before saving, and `formatFromStore` when loading. No config, no setup, no custom revivers.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
localStorage.setItem('profile', formatToStore(profile));
|
|
136
|
+
const profile = formatFromStore(localStorage.getItem('profile'));
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## π οΈ How It Works
|
|
142
|
+
|
|
143
|
+
`formatToStore` adds a tiny type marker to every special value:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"$t": "map",
|
|
148
|
+
"$v": [["key", { "$t": "date", "$v": "2024-10-01T10:30:00.000Z" }]]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
When you call `formatFromStore`, it reads those markers and reconstructs the original types β even deeply nested.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## β¨ Real-World Examples
|
|
157
|
+
|
|
158
|
+
### 1οΈβ£ React: Syncing Complex State to localStorage
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
import { useState } from 'react';
|
|
162
|
+
import { formatToStore, formatFromStore } from 'json-storage-formatter';
|
|
163
|
+
|
|
164
|
+
type WidgetConfig = { location: string; units: string };
|
|
61
165
|
type DashboardConfig = {
|
|
62
166
|
theme: 'light' | 'dark' | 'system';
|
|
63
167
|
widgets: Map<string, WidgetConfig>;
|
|
@@ -65,13 +169,10 @@ type DashboardConfig = {
|
|
|
65
169
|
lastCustomizedAt: Date;
|
|
66
170
|
};
|
|
67
171
|
|
|
68
|
-
|
|
172
|
+
function useDashboardConfig() {
|
|
69
173
|
const [config, setConfig] = useState<DashboardConfig>(() => {
|
|
70
174
|
const json = localStorage.getItem('dashboard-config');
|
|
71
|
-
|
|
72
|
-
if (json) return formatFromStore<DashboardConfig>(json);
|
|
73
|
-
|
|
74
|
-
return getDefaultDashboardConfig();
|
|
175
|
+
return json ? formatFromStore<DashboardConfig>(json) : getDefaultDashboardConfig();
|
|
75
176
|
});
|
|
76
177
|
|
|
77
178
|
const saveConfig = (newConfig: DashboardConfig) => {
|
|
@@ -80,14 +181,14 @@ const useDashboardConfig = () => {
|
|
|
80
181
|
};
|
|
81
182
|
|
|
82
183
|
return { config, saveConfig };
|
|
83
|
-
}
|
|
184
|
+
}
|
|
84
185
|
|
|
85
|
-
//
|
|
186
|
+
// Usage
|
|
86
187
|
const example: DashboardConfig = {
|
|
87
188
|
theme: 'dark',
|
|
88
189
|
widgets: new Map([
|
|
89
190
|
['weather', { location: 'New York', units: 'metric' }],
|
|
90
|
-
['stocks', {
|
|
191
|
+
['stocks', { location: 'NASDAQ', units: 'USD' }],
|
|
91
192
|
]),
|
|
92
193
|
hiddenWidgets: new Set(['news']),
|
|
93
194
|
lastCustomizedAt: new Date(),
|
|
@@ -96,12 +197,10 @@ const example: DashboardConfig = {
|
|
|
96
197
|
|
|
97
198
|
---
|
|
98
199
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
This pattern is common in dashboards, where filters are shared via URL.
|
|
102
|
-
You can safely serialize complex filters (with Dates, Sets, Maps, etc.) and encode them for sharing.
|
|
200
|
+
### 2οΈβ£ React: Syncing Filters via URL (Shareable Dashboard Queries)
|
|
103
201
|
|
|
104
202
|
```tsx
|
|
203
|
+
import { useState } from 'react';
|
|
105
204
|
import { formatToStore, formatFromStore } from 'json-storage-formatter';
|
|
106
205
|
|
|
107
206
|
type DashboardQuery = {
|
|
@@ -110,93 +209,60 @@ type DashboardQuery = {
|
|
|
110
209
|
additionalSettings: Map<string, unknown>;
|
|
111
210
|
};
|
|
112
211
|
|
|
113
|
-
|
|
212
|
+
function useUrlQuery() {
|
|
114
213
|
const [query, setQuery] = useState<DashboardQuery>(() => {
|
|
115
|
-
const params = new URLSearchParams(location.search);
|
|
214
|
+
const params = new URLSearchParams(window.location.search);
|
|
116
215
|
const storedQuery = params.get('query');
|
|
117
|
-
|
|
118
|
-
if (storedQuery) {
|
|
119
|
-
// decode from base64 and restore types
|
|
120
|
-
return formatFromStore<DashboardQuery>(atob(storedQuery));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return getDefaultDashboardQuery();
|
|
216
|
+
return storedQuery ? formatFromStore<DashboardQuery>(atob(storedQuery)) : getDefaultDashboardQuery();
|
|
124
217
|
});
|
|
125
218
|
|
|
126
219
|
const updateQuery = (newQuery: DashboardQuery) => {
|
|
127
220
|
const encoded = btoa(formatToStore(newQuery));
|
|
128
|
-
|
|
129
|
-
// encode the JSON as base64 to make it URL-safe
|
|
130
|
-
// avoids breaking query strings with +, /, or = characters
|
|
131
|
-
window.history.replaceState(null, '', `\${location.pathname}?query=\${encoded}`);
|
|
132
|
-
|
|
221
|
+
window.history.replaceState(null, '', `${window.location.pathname}?query=${encoded}`);
|
|
133
222
|
setQuery(newQuery);
|
|
134
223
|
};
|
|
135
224
|
|
|
136
225
|
return { query, updateQuery };
|
|
137
|
-
}
|
|
226
|
+
}
|
|
138
227
|
```
|
|
139
228
|
|
|
140
|
-
The examples above use React, but the library itself is **framework-agnostic**
|
|
141
|
-
and can be used anywhere in JavaScript or TypeScript projects.
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## π§© Why Itβs Useful
|
|
146
|
-
|
|
147
|
-
This becomes incredibly powerful when your app needs to **sync complex state**
|
|
148
|
-
to a string-based storage layer β like when syncing to **localStorage**, **Redis**, or a **shared dashboard URL**.
|
|
149
|
-
|
|
150
|
-
Instead of being limited by what JSON can handle,
|
|
151
|
-
you can now serialize **any structure** β Maps, Sets, nested objects, or Dates β
|
|
152
|
-
and restore it back without losing context or meaning.
|
|
153
|
-
|
|
154
229
|
---
|
|
155
230
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Under the hood, `formatToStore` adds small metadata markers to every special value.
|
|
159
|
-
Each piece of data gets a structure like this:
|
|
231
|
+
### 3οΈβ£ Framework-Agnostic: Node.js/Backend Example
|
|
160
232
|
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
"$v": [["key", { "$t": "date", "$v": "2024-10-01T10:30:00.000Z" }]]
|
|
165
|
-
}
|
|
166
|
-
```
|
|
233
|
+
```js
|
|
234
|
+
// Save and load any structure in Redis, PostgreSQL, or files
|
|
235
|
+
const { formatToStore, formatFromStore } = require('json-storage-formatter');
|
|
167
236
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
237
|
+
const session = {
|
|
238
|
+
userId: 123,
|
|
239
|
+
expires: new Date(),
|
|
240
|
+
permissions: new Set(['read', 'write']),
|
|
241
|
+
};
|
|
171
242
|
|
|
172
|
-
|
|
243
|
+
// Store in Redis
|
|
244
|
+
redis.set('session:123', formatToStore(session));
|
|
173
245
|
|
|
174
|
-
|
|
175
|
-
|
|
246
|
+
// Later...
|
|
247
|
+
const raw = await redis.get('session:123');
|
|
248
|
+
const restored = formatFromStore(raw);
|
|
249
|
+
// restored.expires is a Date, restored.permissions is a Set
|
|
176
250
|
```
|
|
177
251
|
|
|
178
252
|
---
|
|
179
253
|
|
|
180
|
-
##
|
|
254
|
+
## π§© Supported Types
|
|
181
255
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
Restores the serialized object back to its original types.
|
|
193
|
-
|
|
194
|
-
```ts
|
|
195
|
-
const result = formatFromStore<Map<string, unknown>>(objectWithMetadata);
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Both functions work directly with strings,
|
|
199
|
-
so you can safely use them with localStorage, AsyncStorage, or URLs.
|
|
256
|
+
| Type | Supported? | Restored As |
|
|
257
|
+
| ------------ | ---------- | --------------- |
|
|
258
|
+
| Date | β
| Date |
|
|
259
|
+
| Set | β
| Set |
|
|
260
|
+
| Map | β
| Map |
|
|
261
|
+
| RegExp | β
| RegExp |
|
|
262
|
+
| Error | β
| Error |
|
|
263
|
+
| undefined | β
| undefined |
|
|
264
|
+
| NaN/Infinity | β
| number |
|
|
265
|
+
| Function | β | (not supported) |
|
|
200
266
|
|
|
201
267
|
---
|
|
202
268
|
|
|
@@ -231,15 +297,35 @@ so you can safely use them with localStorage, AsyncStorage, or URLs.
|
|
|
231
297
|
npm install json-storage-formatter
|
|
232
298
|
```
|
|
233
299
|
|
|
234
|
-
or
|
|
235
|
-
|
|
236
300
|
```bash
|
|
237
301
|
yarn add json-storage-formatter
|
|
238
302
|
```
|
|
239
303
|
|
|
240
304
|
---
|
|
241
305
|
|
|
242
|
-
##
|
|
306
|
+
## π API Reference
|
|
307
|
+
|
|
308
|
+
### formatToStore(value)
|
|
309
|
+
|
|
310
|
+
Converts any value into a JSON-safe string with type metadata.
|
|
311
|
+
|
|
312
|
+
### formatFromStore<T>(string)
|
|
313
|
+
|
|
314
|
+
Restores the serialized string back to its original types.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## π‘ Pro Tips
|
|
319
|
+
|
|
320
|
+
- Use with any storage: localStorage, sessionStorage, AsyncStorage, Redis, PostgreSQL JSON columns, URLs, etc.
|
|
321
|
+
- Works with deeply nested structures.
|
|
322
|
+
- Framework-agnostic: use in React, Node.js, or vanilla JS/TS.
|
|
323
|
+
|
|
324
|
+
---
|
|
243
325
|
|
|
244
|
-
|
|
245
|
-
Serialize, store, and restore
|
|
326
|
+
<div align="center">
|
|
327
|
+
<b>Serialize, store, and restore <i>any</i> JavaScript data type β<br />
|
|
328
|
+
without losing its identity. Lightweight. Fast. Reliable.</b>
|
|
329
|
+
<br /><br />
|
|
330
|
+
<a href="https://www.npmjs.com/package/json-storage-formatter">β Try it on NPM</a>
|
|
331
|
+
</div>
|