source: trip-planner-front/node_modules/@discoveryjs/json-ext/src/stringify-info.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.1 KB
Line 
1const {
2 normalizeReplacer,
3 normalizeSpace,
4 replaceValue,
5 getTypeNative,
6 getTypeAsync,
7 isLeadingSurrogate,
8 isTrailingSurrogate,
9 escapableCharCodeSubstitution,
10 type: {
11 PRIMITIVE,
12 OBJECT,
13 ARRAY,
14 PROMISE,
15 STRING_STREAM,
16 OBJECT_STREAM
17 }
18} = require('./utils');
19const charLength2048 = Array.from({ length: 2048 }).map((_, code) => {
20 if (escapableCharCodeSubstitution.hasOwnProperty(code)) {
21 return 2; // \X
22 }
23
24 if (code < 0x20) {
25 return 6; // \uXXXX
26 }
27
28 return code < 128 ? 1 : 2; // UTF8 bytes
29});
30
31function stringLength(str) {
32 let len = 0;
33 let prevLeadingSurrogate = false;
34
35 for (let i = 0; i < str.length; i++) {
36 const code = str.charCodeAt(i);
37
38 if (code < 2048) {
39 len += charLength2048[code];
40 } else if (isLeadingSurrogate(code)) {
41 len += 6; // \uXXXX since no pair with trailing surrogate yet
42 prevLeadingSurrogate = true;
43 continue;
44 } else if (isTrailingSurrogate(code)) {
45 len = prevLeadingSurrogate
46 ? len - 2 // surrogate pair (4 bytes), since we calculate prev leading surrogate as 6 bytes, substruct 2 bytes
47 : len + 6; // \uXXXX
48 } else {
49 len += 3; // code >= 2048 is 3 bytes length for UTF8
50 }
51
52 prevLeadingSurrogate = false;
53 }
54
55 return len + 2; // +2 for quotes
56}
57
58function primitiveLength(value) {
59 switch (typeof value) {
60 case 'string':
61 return stringLength(value);
62
63 case 'number':
64 return Number.isFinite(value) ? String(value).length : 4 /* null */;
65
66 case 'boolean':
67 return value ? 4 /* true */ : 5 /* false */;
68
69 case 'undefined':
70 case 'object':
71 return 4; /* null */
72
73 default:
74 return 0;
75 }
76}
77
78function spaceLength(space) {
79 space = normalizeSpace(space);
80 return typeof space === 'string' ? space.length : 0;
81}
82
83module.exports = function jsonStringifyInfo(value, replacer, space, options) {
84 function walk(holder, key, value) {
85 if (stop) {
86 return;
87 }
88
89 value = replaceValue(holder, key, value, replacer);
90
91 let type = getType(value);
92
93 // check for circular structure
94 if (type !== PRIMITIVE && stack.has(value)) {
95 circular.add(value);
96 length += 4; // treat as null
97
98 if (!options.continueOnCircular) {
99 stop = true;
100 }
101
102 return;
103 }
104
105 switch (type) {
106 case PRIMITIVE:
107 if (value !== undefined || Array.isArray(holder)) {
108 length += primitiveLength(value);
109 } else if (holder === root) {
110 length += 9; // FIXME: that's the length of undefined, should we normalize behaviour to convert it to null?
111 }
112 break;
113
114 case OBJECT: {
115 if (visited.has(value)) {
116 duplicate.add(value);
117 length += visited.get(value);
118 break;
119 }
120
121 const valueLength = length;
122 let entries = 0;
123
124 length += 2; // {}
125
126 stack.add(value);
127
128 for (const key in value) {
129 if (hasOwnProperty.call(value, key) && (allowlist === null || allowlist.has(key))) {
130 const prevLength = length;
131 walk(value, key, value[key]);
132
133 if (prevLength !== length) {
134 // value is printed
135 length += stringLength(key) + 1; // "key":
136 entries++;
137 }
138 }
139 }
140
141 if (entries > 1) {
142 length += entries - 1; // commas
143 }
144
145 stack.delete(value);
146
147 if (space > 0 && entries > 0) {
148 length += (1 + (stack.size + 1) * space + 1) * entries; // for each key-value: \n{space}
149 length += 1 + stack.size * space; // for }
150 }
151
152 visited.set(value, length - valueLength);
153
154 break;
155 }
156
157 case ARRAY: {
158 if (visited.has(value)) {
159 duplicate.add(value);
160 length += visited.get(value);
161 break;
162 }
163
164 const valueLength = length;
165
166 length += 2; // []
167
168 stack.add(value);
169
170 for (let i = 0; i < value.length; i++) {
171 walk(value, i, value[i]);
172 }
173
174 if (value.length > 1) {
175 length += value.length - 1; // commas
176 }
177
178 stack.delete(value);
179
180 if (space > 0 && value.length > 0) {
181 length += (1 + (stack.size + 1) * space) * value.length; // for each element: \n{space}
182 length += 1 + stack.size * space; // for ]
183 }
184
185 visited.set(value, length - valueLength);
186
187 break;
188 }
189
190 case PROMISE:
191 case STRING_STREAM:
192 async.add(value);
193 break;
194
195 case OBJECT_STREAM:
196 length += 2; // []
197 async.add(value);
198 break;
199 }
200 }
201
202 let allowlist = null;
203 replacer = normalizeReplacer(replacer);
204
205 if (Array.isArray(replacer)) {
206 allowlist = new Set(replacer);
207 replacer = null;
208 }
209
210 space = spaceLength(space);
211 options = options || {};
212
213 const visited = new Map();
214 const stack = new Set();
215 const duplicate = new Set();
216 const circular = new Set();
217 const async = new Set();
218 const getType = options.async ? getTypeAsync : getTypeNative;
219 const root = { '': value };
220 let stop = false;
221 let length = 0;
222
223 walk(root, '', value);
224
225 return {
226 minLength: isNaN(length) ? Infinity : length,
227 circular: [...circular],
228 duplicate: [...duplicate],
229 async: [...async]
230 };
231};
Note: See TracBrowser for help on using the repository browser.