json-storage-formatter 3.0.1 β 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 +189 -118
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
const README = `
|
|
2
|
-
|
|
3
1
|
# json-storage-formatter π
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
A **lightweight solution** to store complex JavaScript values as JSON β **without losing their types**. π
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## π€ The Problem
|
|
12
|
-
|
|
13
|
-
When working with tools like **localStorage**, **sessionStorage**, **AsyncStorage**, or even databases like **Redis** or **PostgreSQL (JSON columns)**,
|
|
14
|
-
we often need to store application state or configuration objects as strings using `JSON.stringify`.
|
|
15
|
-
|
|
16
|
-
But thereβs a catch:
|
|
17
|
-
`JSON.stringify` has no idea what to do with values like `Date`, `Map`, or `Set`... It just flattens them into empty objects or strings, and when you parse them back with `JSON.parse`, itβs too late.
|
|
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" />
|
|
18
5
|
|
|
19
|
-
|
|
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>
|
|
20
16
|
|
|
21
17
|
---
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
## π― The Problem
|
|
24
20
|
|
|
25
21
|
```ts
|
|
26
22
|
const userProfile = {
|
|
@@ -45,47 +41,127 @@ console.log(JSON.stringify(userProfile, null, 2));
|
|
|
45
41
|
}
|
|
46
42
|
```
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
**JSON.stringify** loses all type information for Dates, Maps, Sets, RegExps, and more. Your data is flattened, and restoring it is impossible.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
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>
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## π Why Use This Library?
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
- The **Map** disappeared.
|
|
52
|
-
- The **Set** vanished inside the Map.
|
|
57
|
+
## π’ Quick Start
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
### Instantly Store and Restore Complex Data
|
|
55
60
|
|
|
56
61
|
```ts
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
60
84
|
```
|
|
61
85
|
|
|
62
|
-
|
|
63
|
-
Dates, Sets, Maps, RegExps, and even nested structures.
|
|
64
|
-
This forces us to write endless **custom parsers and validators** to recover data
|
|
65
|
-
that could have been automatically restored.
|
|
86
|
+
// Works for any structure: deeply nested, with Dates, Sets, Maps, RegExps, Errors, undefined, NaN, etc.
|
|
66
87
|
|
|
67
88
|
---
|
|
68
89
|
|
|
69
|
-
##
|
|
90
|
+
## π£ Complex Types Example
|
|
70
91
|
|
|
71
|
-
|
|
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
|
+
};
|
|
72
106
|
|
|
73
|
-
|
|
74
|
-
|
|
107
|
+
const stored = formatToStore(complex);
|
|
108
|
+
const restored = formatFromStore<typeof complex>(stored);
|
|
109
|
+
// All types are preserved!
|
|
110
|
+
```
|
|
75
111
|
|
|
76
|
-
|
|
112
|
+
---
|
|
77
113
|
|
|
78
|
-
|
|
114
|
+
### π Type-Safe Storage
|
|
79
115
|
|
|
80
|
-
|
|
116
|
+
Store and restore Maps, Sets, Dates, RegExps, Errors, and more β not just plain objects.
|
|
81
117
|
|
|
82
|
-
|
|
118
|
+
```ts
|
|
119
|
+
import { formatToStore, formatFromStore } from 'json-storage-formatter';
|
|
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
|
|
83
131
|
|
|
84
|
-
|
|
132
|
+
Just call `formatToStore` before saving, and `formatFromStore` when loading. No config, no setup, no custom revivers.
|
|
85
133
|
|
|
86
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';
|
|
87
162
|
import { formatToStore, formatFromStore } from 'json-storage-formatter';
|
|
88
163
|
|
|
164
|
+
type WidgetConfig = { location: string; units: string };
|
|
89
165
|
type DashboardConfig = {
|
|
90
166
|
theme: 'light' | 'dark' | 'system';
|
|
91
167
|
widgets: Map<string, WidgetConfig>;
|
|
@@ -93,30 +169,26 @@ type DashboardConfig = {
|
|
|
93
169
|
lastCustomizedAt: Date;
|
|
94
170
|
};
|
|
95
171
|
|
|
96
|
-
|
|
172
|
+
function useDashboardConfig() {
|
|
97
173
|
const [config, setConfig] = useState<DashboardConfig>(() => {
|
|
98
174
|
const json = localStorage.getItem('dashboard-config');
|
|
99
|
-
|
|
100
|
-
if (json) return formatFromStore<DashboardConfig>(json);
|
|
101
|
-
|
|
102
|
-
return getDefaultDashboardConfig();
|
|
175
|
+
return json ? formatFromStore<DashboardConfig>(json) : getDefaultDashboardConfig();
|
|
103
176
|
});
|
|
104
177
|
|
|
105
178
|
const saveConfig = (newConfig: DashboardConfig) => {
|
|
106
179
|
localStorage.setItem('dashboard-config', formatToStore(newConfig));
|
|
107
|
-
|
|
108
180
|
setConfig(newConfig);
|
|
109
181
|
};
|
|
110
182
|
|
|
111
183
|
return { config, saveConfig };
|
|
112
|
-
}
|
|
184
|
+
}
|
|
113
185
|
|
|
114
|
-
//
|
|
186
|
+
// Usage
|
|
115
187
|
const example: DashboardConfig = {
|
|
116
188
|
theme: 'dark',
|
|
117
189
|
widgets: new Map([
|
|
118
190
|
['weather', { location: 'New York', units: 'metric' }],
|
|
119
|
-
['stocks', {
|
|
191
|
+
['stocks', { location: 'NASDAQ', units: 'USD' }],
|
|
120
192
|
]),
|
|
121
193
|
hiddenWidgets: new Set(['news']),
|
|
122
194
|
lastCustomizedAt: new Date(),
|
|
@@ -125,12 +197,10 @@ const example: DashboardConfig = {
|
|
|
125
197
|
|
|
126
198
|
---
|
|
127
199
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
This pattern is common in dashboards, where filters are shared via URL.
|
|
131
|
-
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)
|
|
132
201
|
|
|
133
202
|
```tsx
|
|
203
|
+
import { useState } from 'react';
|
|
134
204
|
import { formatToStore, formatFromStore } from 'json-storage-formatter';
|
|
135
205
|
|
|
136
206
|
type DashboardQuery = {
|
|
@@ -139,86 +209,60 @@ type DashboardQuery = {
|
|
|
139
209
|
additionalSettings: Map<string, unknown>;
|
|
140
210
|
};
|
|
141
211
|
|
|
142
|
-
|
|
212
|
+
function useUrlQuery() {
|
|
143
213
|
const [query, setQuery] = useState<DashboardQuery>(() => {
|
|
144
|
-
const params = new URLSearchParams(location.search);
|
|
214
|
+
const params = new URLSearchParams(window.location.search);
|
|
145
215
|
const storedQuery = params.get('query');
|
|
146
|
-
|
|
147
|
-
if (storedQuery) {
|
|
148
|
-
// decode from base64 and restore types
|
|
149
|
-
return formatFromStore<DashboardQuery>(atob(storedQuery));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return getDefaultDashboardQuery();
|
|
216
|
+
return storedQuery ? formatFromStore<DashboardQuery>(atob(storedQuery)) : getDefaultDashboardQuery();
|
|
153
217
|
});
|
|
154
218
|
|
|
155
219
|
const updateQuery = (newQuery: DashboardQuery) => {
|
|
156
220
|
const encoded = btoa(formatToStore(newQuery));
|
|
157
|
-
|
|
158
|
-
// encode the json as base64 to make it URL-safe
|
|
159
|
-
window.history.replaceState(null, '', `${location.pathname}?query=${encoded}`);
|
|
160
|
-
|
|
221
|
+
window.history.replaceState(null, '', `${window.location.pathname}?query=${encoded}`);
|
|
161
222
|
setQuery(newQuery);
|
|
162
223
|
};
|
|
163
224
|
|
|
164
225
|
return { query, updateQuery };
|
|
165
|
-
}
|
|
226
|
+
}
|
|
166
227
|
```
|
|
167
228
|
|
|
168
|
-
The examples above are in react but the library is framework-agnostic and can be used anywhere in JavaScript or TypeScript projects.
|
|
169
|
-
|
|
170
|
-
## π§© Why Itβs Useful
|
|
171
|
-
|
|
172
|
-
This becomes incredibly powerful when your app needs to **sync complex state**
|
|
173
|
-
to a string-based storage layer β like when syncing to **localStorage**, **Redis**, or **a shared dashboard URL**.
|
|
174
|
-
|
|
175
|
-
Instead of being limited by what JSON can handle,
|
|
176
|
-
you can now serialize **any structure** β Maps, Sets, nested objects, or Dates β
|
|
177
|
-
and restore it back without losing context or meaning.
|
|
178
|
-
|
|
179
229
|
---
|
|
180
230
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
Under the hood, `formatToStore` adds small metadata markers to every special value.
|
|
184
|
-
Each piece of data gets a structure like this:
|
|
231
|
+
### 3οΈβ£ Framework-Agnostic: Node.js/Backend Example
|
|
185
232
|
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
"$v": [["key", { "$t": "date", "$v": "2024-10-01T10:30:00.000Z" }]]
|
|
190
|
-
}
|
|
191
|
-
```
|
|
233
|
+
```js
|
|
234
|
+
// Save and load any structure in Redis, PostgreSQL, or files
|
|
235
|
+
const { formatToStore, formatFromStore } = require('json-storage-formatter');
|
|
192
236
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
237
|
+
const session = {
|
|
238
|
+
userId: 123,
|
|
239
|
+
expires: new Date(),
|
|
240
|
+
permissions: new Set(['read', 'write']),
|
|
241
|
+
};
|
|
196
242
|
|
|
197
|
-
|
|
243
|
+
// Store in Redis
|
|
244
|
+
redis.set('session:123', formatToStore(session));
|
|
198
245
|
|
|
199
|
-
|
|
200
|
-
|
|
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
|
|
201
250
|
```
|
|
202
251
|
|
|
203
252
|
---
|
|
204
253
|
|
|
205
|
-
##
|
|
254
|
+
## π§© Supported Types
|
|
206
255
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Restores the serialized object back to its original types.
|
|
218
|
-
|
|
219
|
-
```ts
|
|
220
|
-
const result = formatFromStore<Map<string, unknown>>(objectWithMetadata);
|
|
221
|
-
```
|
|
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) |
|
|
222
266
|
|
|
223
267
|
---
|
|
224
268
|
|
|
@@ -236,13 +280,14 @@ const result = formatFromStore<Map<string, unknown>>(objectWithMetadata);
|
|
|
236
280
|
|
|
237
281
|
## βοΈ Comparison
|
|
238
282
|
|
|
239
|
-
| Behavior
|
|
240
|
-
|
|
|
241
|
-
| **Date**
|
|
242
|
-
| **Set**
|
|
243
|
-
| **Map**
|
|
244
|
-
| **
|
|
245
|
-
| **
|
|
283
|
+
| Behavior | JSON.stringify | json-storage-formatter |
|
|
284
|
+
| ------------- | --------------- | ------------------------ |
|
|
285
|
+
| **Date** | Becomes string | β
Restored as Date |
|
|
286
|
+
| **Set** | Lost completely | β
Restored as Set |
|
|
287
|
+
| **Map** | Lost completely | β
Restored as Map |
|
|
288
|
+
| **Undefined** | Omitted | β
Restored as undefined |
|
|
289
|
+
| **Regexp** | Lost completely | β
Restored as RegExp |
|
|
290
|
+
| **Error** | Lost completely | β
Restored as Error |
|
|
246
291
|
|
|
247
292
|
---
|
|
248
293
|
|
|
@@ -252,9 +297,35 @@ const result = formatFromStore<Map<string, unknown>>(objectWithMetadata);
|
|
|
252
297
|
npm install json-storage-formatter
|
|
253
298
|
```
|
|
254
299
|
|
|
300
|
+
```bash
|
|
301
|
+
yarn add json-storage-formatter
|
|
302
|
+
```
|
|
303
|
+
|
|
255
304
|
---
|
|
256
305
|
|
|
257
|
-
##
|
|
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
|
+
---
|
|
258
325
|
|
|
259
|
-
|
|
260
|
-
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>
|