-
Notifications
You must be signed in to change notification settings - Fork 2
/
json.js
76 lines (67 loc) · 2 KB
/
json.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
let stableStringify = require('json-stable-stringify')
const base64Prefix = ':base64:'
// stringifies JSON deterministically, and converts Buffers to
// base64 strings (prefixed with ":base64:")
function stringify(obj) {
let convertedObj = deepClone(obj, bufferToBase64Replacer)
return stableStringify(convertedObj)
}
// parses JSON and converts strings with ":base64:" prefix to Buffers
function parse(json) {
let obj = JSON.parse(json)
return convertBase64ToBuffers(obj)
}
// clones an object, with a replacer function
function deepClone(obj, replacer) {
let newObj = Array.isArray(obj) ? [] : {}
Object.assign(newObj, obj)
for (let key in newObj) {
newObj[key] = replacer(newObj[key])
if (typeof newObj[key] === 'object') {
newObj[key] = deepClone(newObj[key], replacer)
}
}
return newObj
}
function bufferToBase64Replacer(value) {
// convert JSON.stringified Buffer objects to Buffer,
// so they can get encoded to base64
if (
typeof value === 'object' &&
value != null &&
value.type === 'Buffer' &&
Array.isArray(value.data)
) {
value = Buffer.from(value)
}
if (!Buffer.isBuffer(value)) return value
return `${base64Prefix}${value.toString('base64')}`
}
function base64ToBufferReplacer(value) {
if (typeof value !== 'string') return value
if (!value.startsWith(base64Prefix)) return value
return Buffer.from(value.slice(base64Prefix.length), 'base64')
}
function convertBuffersToBase64(obj) {
return replace(obj, bufferToBase64Replacer)
}
function convertBase64ToBuffers(obj) {
return replace(obj, base64ToBufferReplacer)
}
// replaces values in an object without cloning
function replace(obj, replacer) {
for (let key in obj) {
obj[key] = replacer(obj[key])
if (typeof obj[key] === 'object' && !Buffer.isBuffer(obj[key])) {
// recursively replace props of objects (unless it's a Buffer)
replace(obj[key], replacer)
}
}
return obj
}
module.exports = {
stringify,
parse,
convertBuffersToBase64,
convertBase64ToBuffers
}