@augment-vir/common 31.65.0 → 31.66.0
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/dist/augments/json/copy-through-json.d.ts +5 -2
- package/dist/augments/json/copy-through-json.js +4 -1
- package/dist/augments/json/safe-json-stringify.d.ts +17 -0
- package/dist/augments/json/safe-json-stringify.js +25 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/safe-stable-stringify.d.ts +1 -0
- package/dist/safe-stable-stringify.js +600 -0
- package/package.json +3 -3
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type JsonCompatibleValue } from '@augment-vir/core';
|
|
2
|
+
import { type IsUnknown, type Jsonify, type Writable } from 'type-fest';
|
|
2
3
|
/**
|
|
3
4
|
* Deeply copy an object through JSON. This is the fastest deep copy, but the input must already be
|
|
4
5
|
* JSON serializable otherwise the copy will not match the original.
|
|
5
6
|
*
|
|
7
|
+
* Note that this will truncate inputs if they are not safe to serialize.
|
|
8
|
+
*
|
|
6
9
|
* @category JSON : Common
|
|
7
10
|
* @category Copy
|
|
8
11
|
* @category Package : @augment-vir/common
|
|
@@ -31,4 +34,4 @@ import { type Jsonify, type Writable } from 'type-fest';
|
|
|
31
34
|
*
|
|
32
35
|
* @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common)
|
|
33
36
|
*/
|
|
34
|
-
export declare function copyThroughJson<const T>(input: T): Writable<Jsonify<T>>;
|
|
37
|
+
export declare function copyThroughJson<const T>(input: T): IsUnknown<T> extends true ? JsonCompatibleValue : Writable<Jsonify<T>>;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { safeJsonStringify } from './safe-json-stringify.js';
|
|
1
2
|
/**
|
|
2
3
|
* Deeply copy an object through JSON. This is the fastest deep copy, but the input must already be
|
|
3
4
|
* JSON serializable otherwise the copy will not match the original.
|
|
4
5
|
*
|
|
6
|
+
* Note that this will truncate inputs if they are not safe to serialize.
|
|
7
|
+
*
|
|
5
8
|
* @category JSON : Common
|
|
6
9
|
* @category Copy
|
|
7
10
|
* @category Package : @augment-vir/common
|
|
@@ -32,7 +35,7 @@
|
|
|
32
35
|
*/
|
|
33
36
|
export function copyThroughJson(input) {
|
|
34
37
|
try {
|
|
35
|
-
return JSON.parse(
|
|
38
|
+
return JSON.parse(safeJsonStringify(input));
|
|
36
39
|
/* node:coverage ignore next 4 */
|
|
37
40
|
}
|
|
38
41
|
catch (error) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A safe value -> JSON serializer that handles circular references and truncates the depth and
|
|
3
|
+
* breadth of the given value's serialization.
|
|
4
|
+
*
|
|
5
|
+
* @category JSON : Common
|
|
6
|
+
* @category Package : @augment-vir/common
|
|
7
|
+
* @example
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import {safeJsonStringify} from '@augment-vir/common';
|
|
11
|
+
*
|
|
12
|
+
* safeJsonStringify({some: 'value'});
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common)
|
|
16
|
+
*/
|
|
17
|
+
export declare function safeJsonStringify(...params: Parameters<typeof JSON.stringify>): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { configure } from '../../safe-stable-stringify.js';
|
|
2
|
+
const safeStringify = configure({
|
|
3
|
+
maximumDepth: 15,
|
|
4
|
+
maximumBreadth: 50,
|
|
5
|
+
});
|
|
6
|
+
/**
|
|
7
|
+
* A safe value -> JSON serializer that handles circular references and truncates the depth and
|
|
8
|
+
* breadth of the given value's serialization.
|
|
9
|
+
*
|
|
10
|
+
* @category JSON : Common
|
|
11
|
+
* @category Package : @augment-vir/common
|
|
12
|
+
* @example
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import {safeJsonStringify} from '@augment-vir/common';
|
|
16
|
+
*
|
|
17
|
+
* safeJsonStringify({some: 'value'});
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common)
|
|
21
|
+
*/
|
|
22
|
+
export function safeJsonStringify(...params) {
|
|
23
|
+
/* node:coverage disable: idk how to get this to return `undefined`. */
|
|
24
|
+
return safeStringify(...params) || '';
|
|
25
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export * from './augments/json/append-json.js';
|
|
|
29
29
|
export * from './augments/json/copy-through-json.js';
|
|
30
30
|
export * from './augments/json/json5.js';
|
|
31
31
|
export * from './augments/json/jsonify.js';
|
|
32
|
+
export * from './augments/json/safe-json-stringify.js';
|
|
32
33
|
export * from './augments/log/log-colors.js';
|
|
33
34
|
export * from './augments/log/log-countdown.js';
|
|
34
35
|
export * from './augments/log/log-string.js';
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,7 @@ export * from './augments/json/append-json.js';
|
|
|
29
29
|
export * from './augments/json/copy-through-json.js';
|
|
30
30
|
export * from './augments/json/json5.js';
|
|
31
31
|
export * from './augments/json/jsonify.js';
|
|
32
|
+
export * from './augments/json/safe-json-stringify.js';
|
|
32
33
|
export * from './augments/log/log-colors.js';
|
|
33
34
|
export * from './augments/log/log-countdown.js';
|
|
34
35
|
export * from './augments/log/log-string.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function configure(options: any): (value: any, replacer: any, space: any) => any;
|
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
/* node:coverage disable */
|
|
2
|
+
/**
|
|
3
|
+
* This file is copied from the
|
|
4
|
+
* [safe-stable-stringify](https://npmjs.com/package/safe-stable-stringify) package, and modified so
|
|
5
|
+
* that it can actually be imported, at:
|
|
6
|
+
* https://github.com/BridgeAR/safe-stable-stringify/blob/8a02137ac933eff57dd6e49beb9ee766fe8dd372/index.js
|
|
7
|
+
*
|
|
8
|
+
* It has the following license:
|
|
9
|
+
*
|
|
10
|
+
* The MIT License (MIT)
|
|
11
|
+
*
|
|
12
|
+
* Copyright (c) Ruben Bridgewater
|
|
13
|
+
*
|
|
14
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
* in the Software without restriction, including without limitation the rights
|
|
17
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
* furnished to do so, subject to the following conditions:
|
|
20
|
+
*
|
|
21
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
* copies or substantial portions of the Software.
|
|
23
|
+
*
|
|
24
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
* SOFTWARE.
|
|
31
|
+
*/
|
|
32
|
+
/* eslint-disable */
|
|
33
|
+
// @ts-nocheck
|
|
34
|
+
const { hasOwnProperty } = Object.prototype;
|
|
35
|
+
const strEscapeSequencesRegExp = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/;
|
|
36
|
+
// Escape C0 control characters, double quotes, the backslash and every code
|
|
37
|
+
// unit with a numeric value in the inclusive range 0xD800 to 0xDFFF.
|
|
38
|
+
function strEscape(str) {
|
|
39
|
+
// Some magic numbers that worked out fine while benchmarking with v8 8.0
|
|
40
|
+
if (str.length < 5000 && !strEscapeSequencesRegExp.test(str)) {
|
|
41
|
+
return `"${str}"`;
|
|
42
|
+
}
|
|
43
|
+
return JSON.stringify(str);
|
|
44
|
+
}
|
|
45
|
+
function sort(array, comparator) {
|
|
46
|
+
// Insertion sort is very efficient for small input sizes, but it has a bad
|
|
47
|
+
// worst case complexity. Thus, use native array sort for bigger values.
|
|
48
|
+
if (array.length > 2e2 || comparator) {
|
|
49
|
+
return array.sort(comparator);
|
|
50
|
+
}
|
|
51
|
+
for (let i = 1; i < array.length; i++) {
|
|
52
|
+
const currentValue = array[i];
|
|
53
|
+
let position = i;
|
|
54
|
+
while (position !== 0 && array[position - 1] > currentValue) {
|
|
55
|
+
array[position] = array[position - 1];
|
|
56
|
+
position--;
|
|
57
|
+
}
|
|
58
|
+
array[position] = currentValue;
|
|
59
|
+
}
|
|
60
|
+
return array;
|
|
61
|
+
}
|
|
62
|
+
const typedArrayPrototypeGetSymbolToStringTag = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Object.getPrototypeOf(new Int8Array())), Symbol.toStringTag).get;
|
|
63
|
+
function isTypedArrayWithEntries(value) {
|
|
64
|
+
return typedArrayPrototypeGetSymbolToStringTag.call(value) !== undefined && value.length !== 0;
|
|
65
|
+
}
|
|
66
|
+
function stringifyTypedArray(array, separator, maximumBreadth) {
|
|
67
|
+
if (array.length < maximumBreadth) {
|
|
68
|
+
maximumBreadth = array.length;
|
|
69
|
+
}
|
|
70
|
+
const whitespace = separator === ',' ? '' : ' ';
|
|
71
|
+
let res = `"0":${whitespace}${array[0]}`;
|
|
72
|
+
for (let i = 1; i < maximumBreadth; i++) {
|
|
73
|
+
res += `${separator}"${i}":${whitespace}${array[i]}`;
|
|
74
|
+
}
|
|
75
|
+
return res;
|
|
76
|
+
}
|
|
77
|
+
function getCircularValueOption(options) {
|
|
78
|
+
if (hasOwnProperty.call(options, 'circularValue')) {
|
|
79
|
+
const circularValue = options.circularValue;
|
|
80
|
+
if (typeof circularValue === 'string') {
|
|
81
|
+
return `"${circularValue}"`;
|
|
82
|
+
}
|
|
83
|
+
if (circularValue == null) {
|
|
84
|
+
return circularValue;
|
|
85
|
+
}
|
|
86
|
+
if (circularValue === Error || circularValue === TypeError) {
|
|
87
|
+
return {
|
|
88
|
+
toString() {
|
|
89
|
+
throw new TypeError('Converting circular structure to JSON');
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
throw new TypeError('The "circularValue" argument must be of type string or the value null or undefined');
|
|
94
|
+
}
|
|
95
|
+
return '"[Circular]"';
|
|
96
|
+
}
|
|
97
|
+
function getDeterministicOption(options) {
|
|
98
|
+
let value;
|
|
99
|
+
if (hasOwnProperty.call(options, 'deterministic')) {
|
|
100
|
+
value = options.deterministic;
|
|
101
|
+
if (typeof value !== 'boolean' && typeof value !== 'function') {
|
|
102
|
+
throw new TypeError('The "deterministic" argument must be of type boolean or comparator function');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return value === undefined ? true : value;
|
|
106
|
+
}
|
|
107
|
+
function getBooleanOption(options, key) {
|
|
108
|
+
let value;
|
|
109
|
+
if (hasOwnProperty.call(options, key)) {
|
|
110
|
+
value = options[key];
|
|
111
|
+
if (typeof value !== 'boolean') {
|
|
112
|
+
throw new TypeError(`The "${key}" argument must be of type boolean`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return value === undefined ? true : value;
|
|
116
|
+
}
|
|
117
|
+
function getPositiveIntegerOption(options, key) {
|
|
118
|
+
let value;
|
|
119
|
+
if (hasOwnProperty.call(options, key)) {
|
|
120
|
+
value = options[key];
|
|
121
|
+
if (typeof value !== 'number') {
|
|
122
|
+
throw new TypeError(`The "${key}" argument must be of type number`);
|
|
123
|
+
}
|
|
124
|
+
if (!Number.isInteger(value)) {
|
|
125
|
+
throw new TypeError(`The "${key}" argument must be an integer`);
|
|
126
|
+
}
|
|
127
|
+
if (value < 1) {
|
|
128
|
+
throw new RangeError(`The "${key}" argument must be >= 1`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return value === undefined ? Infinity : value;
|
|
132
|
+
}
|
|
133
|
+
function getItemCount(number) {
|
|
134
|
+
if (number === 1) {
|
|
135
|
+
return '1 item';
|
|
136
|
+
}
|
|
137
|
+
return `${number} items`;
|
|
138
|
+
}
|
|
139
|
+
function getUniqueReplacerSet(replacerArray) {
|
|
140
|
+
const replacerSet = new Set();
|
|
141
|
+
for (const value of replacerArray) {
|
|
142
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
143
|
+
replacerSet.add(String(value));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return replacerSet;
|
|
147
|
+
}
|
|
148
|
+
function getStrictOption(options) {
|
|
149
|
+
if (hasOwnProperty.call(options, 'strict')) {
|
|
150
|
+
const value = options.strict;
|
|
151
|
+
if (typeof value !== 'boolean') {
|
|
152
|
+
throw new TypeError('The "strict" argument must be of type boolean');
|
|
153
|
+
}
|
|
154
|
+
if (value) {
|
|
155
|
+
return (value) => {
|
|
156
|
+
let message = `Object can not safely be stringified. Received type ${typeof value}`;
|
|
157
|
+
if (typeof value !== 'function') {
|
|
158
|
+
message += ` (${value.toString()})`;
|
|
159
|
+
}
|
|
160
|
+
throw new Error(message);
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export function configure(options) {
|
|
166
|
+
options = { ...options };
|
|
167
|
+
const fail = getStrictOption(options);
|
|
168
|
+
if (fail) {
|
|
169
|
+
if (options.bigint === undefined) {
|
|
170
|
+
options.bigint = false;
|
|
171
|
+
}
|
|
172
|
+
if (!('circularValue' in options)) {
|
|
173
|
+
options.circularValue = Error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const circularValue = getCircularValueOption(options);
|
|
177
|
+
const bigint = getBooleanOption(options, 'bigint');
|
|
178
|
+
const deterministic = getDeterministicOption(options);
|
|
179
|
+
const comparator = typeof deterministic === 'function' ? deterministic : undefined;
|
|
180
|
+
const maximumDepth = getPositiveIntegerOption(options, 'maximumDepth');
|
|
181
|
+
const maximumBreadth = getPositiveIntegerOption(options, 'maximumBreadth');
|
|
182
|
+
function stringifyFnReplacer(key, parent, stack, replacer, spacer, indentation) {
|
|
183
|
+
let value = parent[key];
|
|
184
|
+
if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {
|
|
185
|
+
value = value.toJSON(key);
|
|
186
|
+
}
|
|
187
|
+
value = replacer.call(parent, key, value);
|
|
188
|
+
switch (typeof value) {
|
|
189
|
+
case 'string':
|
|
190
|
+
return strEscape(value);
|
|
191
|
+
case 'object': {
|
|
192
|
+
if (value === null) {
|
|
193
|
+
return 'null';
|
|
194
|
+
}
|
|
195
|
+
if (stack.includes(value)) {
|
|
196
|
+
return circularValue;
|
|
197
|
+
}
|
|
198
|
+
let res = '';
|
|
199
|
+
let join = ',';
|
|
200
|
+
const originalIndentation = indentation;
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
if (value.length === 0) {
|
|
203
|
+
return '[]';
|
|
204
|
+
}
|
|
205
|
+
if (maximumDepth < stack.length + 1) {
|
|
206
|
+
return '"[Array]"';
|
|
207
|
+
}
|
|
208
|
+
stack.push(value);
|
|
209
|
+
if (spacer !== '') {
|
|
210
|
+
indentation += spacer;
|
|
211
|
+
res += `\n${indentation}`;
|
|
212
|
+
join = `,\n${indentation}`;
|
|
213
|
+
}
|
|
214
|
+
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
215
|
+
let i = 0;
|
|
216
|
+
for (; i < maximumValuesToStringify - 1; i++) {
|
|
217
|
+
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
218
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
219
|
+
res += join;
|
|
220
|
+
}
|
|
221
|
+
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
222
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
223
|
+
if (value.length - 1 > maximumBreadth) {
|
|
224
|
+
const removedKeys = value.length - maximumBreadth - 1;
|
|
225
|
+
res += `${join}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
226
|
+
}
|
|
227
|
+
if (spacer !== '') {
|
|
228
|
+
res += `\n${originalIndentation}`;
|
|
229
|
+
}
|
|
230
|
+
stack.pop();
|
|
231
|
+
return `[${res}]`;
|
|
232
|
+
}
|
|
233
|
+
let keys = Object.keys(value);
|
|
234
|
+
const keyLength = keys.length;
|
|
235
|
+
if (keyLength === 0) {
|
|
236
|
+
return '{}';
|
|
237
|
+
}
|
|
238
|
+
if (maximumDepth < stack.length + 1) {
|
|
239
|
+
return '"[Object]"';
|
|
240
|
+
}
|
|
241
|
+
let whitespace = '';
|
|
242
|
+
let separator = '';
|
|
243
|
+
if (spacer !== '') {
|
|
244
|
+
indentation += spacer;
|
|
245
|
+
join = `,\n${indentation}`;
|
|
246
|
+
whitespace = ' ';
|
|
247
|
+
}
|
|
248
|
+
const maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
249
|
+
if (deterministic && !isTypedArrayWithEntries(value)) {
|
|
250
|
+
keys = sort(keys, comparator);
|
|
251
|
+
}
|
|
252
|
+
stack.push(value);
|
|
253
|
+
for (let i = 0; i < maximumPropertiesToStringify; i++) {
|
|
254
|
+
const key = keys[i];
|
|
255
|
+
const tmp = stringifyFnReplacer(key, value, stack, replacer, spacer, indentation);
|
|
256
|
+
if (tmp !== undefined) {
|
|
257
|
+
res += `${separator}${strEscape(key)}:${whitespace}${tmp}`;
|
|
258
|
+
separator = join;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (keyLength > maximumBreadth) {
|
|
262
|
+
const removedKeys = keyLength - maximumBreadth;
|
|
263
|
+
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
264
|
+
separator = join;
|
|
265
|
+
}
|
|
266
|
+
if (spacer !== '' && separator.length > 1) {
|
|
267
|
+
res = `\n${indentation}${res}\n${originalIndentation}`;
|
|
268
|
+
}
|
|
269
|
+
stack.pop();
|
|
270
|
+
return `{${res}}`;
|
|
271
|
+
}
|
|
272
|
+
case 'number':
|
|
273
|
+
return isFinite(value) ? String(value) : fail ? fail(value) : 'null';
|
|
274
|
+
case 'boolean':
|
|
275
|
+
return value ? 'true' : 'false';
|
|
276
|
+
case 'undefined':
|
|
277
|
+
return undefined;
|
|
278
|
+
case 'bigint':
|
|
279
|
+
if (bigint) {
|
|
280
|
+
return String(value);
|
|
281
|
+
}
|
|
282
|
+
// fallthrough
|
|
283
|
+
default:
|
|
284
|
+
return fail ? fail(value) : undefined;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function stringifyArrayReplacer(key, value, stack, replacer, spacer, indentation) {
|
|
288
|
+
if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {
|
|
289
|
+
value = value.toJSON(key);
|
|
290
|
+
}
|
|
291
|
+
switch (typeof value) {
|
|
292
|
+
case 'string':
|
|
293
|
+
return strEscape(value);
|
|
294
|
+
case 'object': {
|
|
295
|
+
if (value === null) {
|
|
296
|
+
return 'null';
|
|
297
|
+
}
|
|
298
|
+
if (stack.includes(value)) {
|
|
299
|
+
return circularValue;
|
|
300
|
+
}
|
|
301
|
+
const originalIndentation = indentation;
|
|
302
|
+
let res = '';
|
|
303
|
+
let join = ',';
|
|
304
|
+
if (Array.isArray(value)) {
|
|
305
|
+
if (value.length === 0) {
|
|
306
|
+
return '[]';
|
|
307
|
+
}
|
|
308
|
+
if (maximumDepth < stack.length + 1) {
|
|
309
|
+
return '"[Array]"';
|
|
310
|
+
}
|
|
311
|
+
stack.push(value);
|
|
312
|
+
if (spacer !== '') {
|
|
313
|
+
indentation += spacer;
|
|
314
|
+
res += `\n${indentation}`;
|
|
315
|
+
join = `,\n${indentation}`;
|
|
316
|
+
}
|
|
317
|
+
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
318
|
+
let i = 0;
|
|
319
|
+
for (; i < maximumValuesToStringify - 1; i++) {
|
|
320
|
+
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
321
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
322
|
+
res += join;
|
|
323
|
+
}
|
|
324
|
+
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
325
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
326
|
+
if (value.length - 1 > maximumBreadth) {
|
|
327
|
+
const removedKeys = value.length - maximumBreadth - 1;
|
|
328
|
+
res += `${join}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
329
|
+
}
|
|
330
|
+
if (spacer !== '') {
|
|
331
|
+
res += `\n${originalIndentation}`;
|
|
332
|
+
}
|
|
333
|
+
stack.pop();
|
|
334
|
+
return `[${res}]`;
|
|
335
|
+
}
|
|
336
|
+
stack.push(value);
|
|
337
|
+
let whitespace = '';
|
|
338
|
+
if (spacer !== '') {
|
|
339
|
+
indentation += spacer;
|
|
340
|
+
join = `,\n${indentation}`;
|
|
341
|
+
whitespace = ' ';
|
|
342
|
+
}
|
|
343
|
+
let separator = '';
|
|
344
|
+
for (const key of replacer) {
|
|
345
|
+
const tmp = stringifyArrayReplacer(key, value[key], stack, replacer, spacer, indentation);
|
|
346
|
+
if (tmp !== undefined) {
|
|
347
|
+
res += `${separator}${strEscape(key)}:${whitespace}${tmp}`;
|
|
348
|
+
separator = join;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (spacer !== '' && separator.length > 1) {
|
|
352
|
+
res = `\n${indentation}${res}\n${originalIndentation}`;
|
|
353
|
+
}
|
|
354
|
+
stack.pop();
|
|
355
|
+
return `{${res}}`;
|
|
356
|
+
}
|
|
357
|
+
case 'number':
|
|
358
|
+
return isFinite(value) ? String(value) : fail ? fail(value) : 'null';
|
|
359
|
+
case 'boolean':
|
|
360
|
+
return value ? 'true' : 'false';
|
|
361
|
+
case 'undefined':
|
|
362
|
+
return undefined;
|
|
363
|
+
case 'bigint':
|
|
364
|
+
if (bigint) {
|
|
365
|
+
return String(value);
|
|
366
|
+
}
|
|
367
|
+
// fallthrough
|
|
368
|
+
default:
|
|
369
|
+
return fail ? fail(value) : undefined;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function stringifyIndent(key, value, stack, spacer, indentation) {
|
|
373
|
+
switch (typeof value) {
|
|
374
|
+
case 'string':
|
|
375
|
+
return strEscape(value);
|
|
376
|
+
case 'object': {
|
|
377
|
+
if (value === null) {
|
|
378
|
+
return 'null';
|
|
379
|
+
}
|
|
380
|
+
if (typeof value.toJSON === 'function') {
|
|
381
|
+
value = value.toJSON(key);
|
|
382
|
+
// Prevent calling `toJSON` again.
|
|
383
|
+
if (typeof value !== 'object') {
|
|
384
|
+
return stringifyIndent(key, value, stack, spacer, indentation);
|
|
385
|
+
}
|
|
386
|
+
if (value === null) {
|
|
387
|
+
return 'null';
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (stack.includes(value)) {
|
|
391
|
+
return circularValue;
|
|
392
|
+
}
|
|
393
|
+
const originalIndentation = indentation;
|
|
394
|
+
if (Array.isArray(value)) {
|
|
395
|
+
if (value.length === 0) {
|
|
396
|
+
return '[]';
|
|
397
|
+
}
|
|
398
|
+
if (maximumDepth < stack.length + 1) {
|
|
399
|
+
return '"[Array]"';
|
|
400
|
+
}
|
|
401
|
+
stack.push(value);
|
|
402
|
+
indentation += spacer;
|
|
403
|
+
let res = `\n${indentation}`;
|
|
404
|
+
const join = `,\n${indentation}`;
|
|
405
|
+
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
406
|
+
let i = 0;
|
|
407
|
+
for (; i < maximumValuesToStringify - 1; i++) {
|
|
408
|
+
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
409
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
410
|
+
res += join;
|
|
411
|
+
}
|
|
412
|
+
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
413
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
414
|
+
if (value.length - 1 > maximumBreadth) {
|
|
415
|
+
const removedKeys = value.length - maximumBreadth - 1;
|
|
416
|
+
res += `${join}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
417
|
+
}
|
|
418
|
+
res += `\n${originalIndentation}`;
|
|
419
|
+
stack.pop();
|
|
420
|
+
return `[${res}]`;
|
|
421
|
+
}
|
|
422
|
+
let keys = Object.keys(value);
|
|
423
|
+
const keyLength = keys.length;
|
|
424
|
+
if (keyLength === 0) {
|
|
425
|
+
return '{}';
|
|
426
|
+
}
|
|
427
|
+
if (maximumDepth < stack.length + 1) {
|
|
428
|
+
return '"[Object]"';
|
|
429
|
+
}
|
|
430
|
+
indentation += spacer;
|
|
431
|
+
const join = `,\n${indentation}`;
|
|
432
|
+
let res = '';
|
|
433
|
+
let separator = '';
|
|
434
|
+
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
435
|
+
if (isTypedArrayWithEntries(value)) {
|
|
436
|
+
res += stringifyTypedArray(value, join, maximumBreadth);
|
|
437
|
+
keys = keys.slice(value.length);
|
|
438
|
+
maximumPropertiesToStringify -= value.length;
|
|
439
|
+
separator = join;
|
|
440
|
+
}
|
|
441
|
+
if (deterministic) {
|
|
442
|
+
keys = sort(keys, comparator);
|
|
443
|
+
}
|
|
444
|
+
stack.push(value);
|
|
445
|
+
for (let i = 0; i < maximumPropertiesToStringify; i++) {
|
|
446
|
+
const key = keys[i];
|
|
447
|
+
const tmp = stringifyIndent(key, value[key], stack, spacer, indentation);
|
|
448
|
+
if (tmp !== undefined) {
|
|
449
|
+
res += `${separator}${strEscape(key)}: ${tmp}`;
|
|
450
|
+
separator = join;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (keyLength > maximumBreadth) {
|
|
454
|
+
const removedKeys = keyLength - maximumBreadth;
|
|
455
|
+
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
456
|
+
separator = join;
|
|
457
|
+
}
|
|
458
|
+
if (separator !== '') {
|
|
459
|
+
res = `\n${indentation}${res}\n${originalIndentation}`;
|
|
460
|
+
}
|
|
461
|
+
stack.pop();
|
|
462
|
+
return `{${res}}`;
|
|
463
|
+
}
|
|
464
|
+
case 'number':
|
|
465
|
+
return isFinite(value) ? String(value) : fail ? fail(value) : 'null';
|
|
466
|
+
case 'boolean':
|
|
467
|
+
return value ? 'true' : 'false';
|
|
468
|
+
case 'undefined':
|
|
469
|
+
return undefined;
|
|
470
|
+
case 'bigint':
|
|
471
|
+
if (bigint) {
|
|
472
|
+
return String(value);
|
|
473
|
+
}
|
|
474
|
+
// fallthrough
|
|
475
|
+
default:
|
|
476
|
+
return fail ? fail(value) : undefined;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function stringifySimple(key, value, stack) {
|
|
480
|
+
switch (typeof value) {
|
|
481
|
+
case 'string':
|
|
482
|
+
return strEscape(value);
|
|
483
|
+
case 'object': {
|
|
484
|
+
if (value === null) {
|
|
485
|
+
return 'null';
|
|
486
|
+
}
|
|
487
|
+
if (typeof value.toJSON === 'function') {
|
|
488
|
+
value = value.toJSON(key);
|
|
489
|
+
// Prevent calling `toJSON` again
|
|
490
|
+
if (typeof value !== 'object') {
|
|
491
|
+
return stringifySimple(key, value, stack);
|
|
492
|
+
}
|
|
493
|
+
if (value === null) {
|
|
494
|
+
return 'null';
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (stack.includes(value)) {
|
|
498
|
+
return circularValue;
|
|
499
|
+
}
|
|
500
|
+
let res = '';
|
|
501
|
+
const hasLength = value.length !== undefined;
|
|
502
|
+
if (hasLength && Array.isArray(value)) {
|
|
503
|
+
if (value.length === 0) {
|
|
504
|
+
return '[]';
|
|
505
|
+
}
|
|
506
|
+
if (maximumDepth < stack.length + 1) {
|
|
507
|
+
return '"[Array]"';
|
|
508
|
+
}
|
|
509
|
+
stack.push(value);
|
|
510
|
+
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
511
|
+
let i = 0;
|
|
512
|
+
for (; i < maximumValuesToStringify - 1; i++) {
|
|
513
|
+
const tmp = stringifySimple(String(i), value[i], stack);
|
|
514
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
515
|
+
res += ',';
|
|
516
|
+
}
|
|
517
|
+
const tmp = stringifySimple(String(i), value[i], stack);
|
|
518
|
+
res += tmp === undefined ? 'null' : tmp;
|
|
519
|
+
if (value.length - 1 > maximumBreadth) {
|
|
520
|
+
const removedKeys = value.length - maximumBreadth - 1;
|
|
521
|
+
res += `,"... ${getItemCount(removedKeys)} not stringified"`;
|
|
522
|
+
}
|
|
523
|
+
stack.pop();
|
|
524
|
+
return `[${res}]`;
|
|
525
|
+
}
|
|
526
|
+
let keys = Object.keys(value);
|
|
527
|
+
const keyLength = keys.length;
|
|
528
|
+
if (keyLength === 0) {
|
|
529
|
+
return '{}';
|
|
530
|
+
}
|
|
531
|
+
if (maximumDepth < stack.length + 1) {
|
|
532
|
+
return '"[Object]"';
|
|
533
|
+
}
|
|
534
|
+
let separator = '';
|
|
535
|
+
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
536
|
+
if (hasLength && isTypedArrayWithEntries(value)) {
|
|
537
|
+
res += stringifyTypedArray(value, ',', maximumBreadth);
|
|
538
|
+
keys = keys.slice(value.length);
|
|
539
|
+
maximumPropertiesToStringify -= value.length;
|
|
540
|
+
separator = ',';
|
|
541
|
+
}
|
|
542
|
+
if (deterministic) {
|
|
543
|
+
keys = sort(keys, comparator);
|
|
544
|
+
}
|
|
545
|
+
stack.push(value);
|
|
546
|
+
for (let i = 0; i < maximumPropertiesToStringify; i++) {
|
|
547
|
+
const key = keys[i];
|
|
548
|
+
const tmp = stringifySimple(key, value[key], stack);
|
|
549
|
+
if (tmp !== undefined) {
|
|
550
|
+
res += `${separator}${strEscape(key)}:${tmp}`;
|
|
551
|
+
separator = ',';
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (keyLength > maximumBreadth) {
|
|
555
|
+
const removedKeys = keyLength - maximumBreadth;
|
|
556
|
+
res += `${separator}"...":"${getItemCount(removedKeys)} not stringified"`;
|
|
557
|
+
}
|
|
558
|
+
stack.pop();
|
|
559
|
+
return `{${res}}`;
|
|
560
|
+
}
|
|
561
|
+
case 'number':
|
|
562
|
+
return isFinite(value) ? String(value) : fail ? fail(value) : 'null';
|
|
563
|
+
case 'boolean':
|
|
564
|
+
return value ? 'true' : 'false';
|
|
565
|
+
case 'undefined':
|
|
566
|
+
return undefined;
|
|
567
|
+
case 'bigint':
|
|
568
|
+
if (bigint) {
|
|
569
|
+
return String(value);
|
|
570
|
+
}
|
|
571
|
+
// fallthrough
|
|
572
|
+
default:
|
|
573
|
+
return fail ? fail(value) : undefined;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
function stringify(value, replacer, space) {
|
|
577
|
+
if (arguments.length > 1) {
|
|
578
|
+
let spacer = '';
|
|
579
|
+
if (typeof space === 'number') {
|
|
580
|
+
spacer = ' '.repeat(Math.min(space, 10));
|
|
581
|
+
}
|
|
582
|
+
else if (typeof space === 'string') {
|
|
583
|
+
spacer = space.slice(0, 10);
|
|
584
|
+
}
|
|
585
|
+
if (replacer != null) {
|
|
586
|
+
if (typeof replacer === 'function') {
|
|
587
|
+
return stringifyFnReplacer('', { '': value }, [], replacer, spacer, '');
|
|
588
|
+
}
|
|
589
|
+
if (Array.isArray(replacer)) {
|
|
590
|
+
return stringifyArrayReplacer('', value, [], getUniqueReplacerSet(replacer), spacer, '');
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (spacer.length !== 0) {
|
|
594
|
+
return stringifyIndent('', value, [], spacer, '');
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return stringifySimple('', value, []);
|
|
598
|
+
}
|
|
599
|
+
return stringify;
|
|
600
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@augment-vir/common",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.66.0",
|
|
4
4
|
"description": "A collection of augments, helpers types, functions, and classes for any JavaScript environment.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"augment",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"test:web": "virmator --no-deps test web"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@augment-vir/assert": "^31.
|
|
44
|
-
"@augment-vir/core": "^31.
|
|
43
|
+
"@augment-vir/assert": "^31.66.0",
|
|
44
|
+
"@augment-vir/core": "^31.66.0",
|
|
45
45
|
"@date-vir/duration": "^8.1.1",
|
|
46
46
|
"ansi-styles": "^6.2.3",
|
|
47
47
|
"deepcopy-esm": "^2.1.1",
|