decycle.js
2.55 KB
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { DecycleError } from './errors';
import getPropertiesList from './util/getPropertiesList';
import typeReplacer from './util/typeReplacer';
import omitProperty from './util/omitProperty';
import { CYCLIC_KEY } from '../constants';
import { objectType } from './types';
import { DEPTH_KEY } from './types/object/configureDepth';
const { hasOwnProperty } = Object.prototype;
export default function decycle(object, depth = 10) {
const objects = new WeakMap();
let isCyclic = false;
const res = (function derez(value, path, _depth, _branchDepthMax) {
let oldPath;
let obj;
let maxDepth = _branchDepthMax;
const result = typeReplacer(value);
if (result) {
return result.value;
}
const type = typeof value;
if (value instanceof Boolean || value instanceof Number || value instanceof String) {
return value;
}
if (type === 'object' && value !== null) {
oldPath = objects.get(value);
if (oldPath !== undefined) {
isCyclic = true;
return { $ref: oldPath };
}
try {
objects.set(value, path);
} catch (error) {
console.error(error); // eslint-disable-line no-console
return new DecycleError(error.message);
}
if (Array.isArray(value)) {
obj = [];
for (let i = 0; i < value.length; i += 1) {
obj[i] = derez(value[i], `${path}[${i}]`, _depth + 1, maxDepth);
}
} else {
obj = objectType.serialize(value);
let newDepth;
if (hasOwnProperty.call(obj, DEPTH_KEY)) {
if (_depth + 1 < maxDepth) {
const depthKey = obj[DEPTH_KEY];
newDepth = depthKey === 0 ? 0 : _depth + depthKey;
maxDepth = newDepth >= depth ? depth : newDepth;
}
delete obj[DEPTH_KEY];
}
if (_depth <= maxDepth) {
getPropertiesList(value).forEach(name => {
if (!omitProperty(name)) {
try {
obj[name] = derez(
value[name],
`${path}[${JSON.stringify(name)}]`,
_depth + 1,
maxDepth
);
} catch (error) {
console.error(error); // eslint-disable-line no-console
obj[name] = new DecycleError(error.message);
}
}
});
}
}
if (_depth === 0 && value instanceof Object && isCyclic) {
obj[CYCLIC_KEY] = true;
}
return obj;
}
return value;
})(object, '$', 0, depth);
return res;
}