UNPKG

3.96 kBJavaScriptView Raw
1// deno-lint-ignore-file no-explicit-any no-empty
2import { asyncIterToStream } from 'whatwg-stream-to-async-iter';
3export const isIterable = (x) => x != null && typeof x === 'object' && Symbol.iterator in x;
4export const isAsyncIterable = (x) => x != null && typeof x === 'object' && Symbol.asyncIterator in x;
5const isPromiseLike = (x) => x != null && typeof x === 'object' && 'then' in x && typeof x.then === 'function';
6const isToJSON = (x) => x != null && typeof x === 'object' && 'toJSON' in x;
7const safeAdd = (seen, value) => {
8 if (seen.has(value))
9 throw TypeError('Converting circular structure to JSON');
10 seen.add(value);
11};
12const check = (v) => {
13 if (v === undefined)
14 return false;
15 const type = typeof v;
16 return type !== 'function' && type !== 'symbol';
17};
18// TODO: Add replacer
19// TODO: add formatting/spaces
20// TODO: concurrent objects/arrays
21/**
22 * @deprecated Change name to something more descriptive!?
23 */
24export async function* jsonStringifyGenerator(value, seen = new WeakSet()) {
25 if (isAsyncIterable(value)) {
26 yield '[';
27 safeAdd(seen, value);
28 let first = true;
29 for await (const v of value) {
30 if (!first)
31 yield ',';
32 else
33 first = false;
34 yield* jsonStringifyGenerator(v, seen);
35 }
36 seen.delete(value);
37 yield ']';
38 }
39 else if (isPromiseLike(value)) {
40 const v = await value;
41 if (check(v)) {
42 safeAdd(seen, value);
43 yield* jsonStringifyGenerator(v, seen);
44 seen.delete(value);
45 }
46 }
47 else if (isToJSON(value)) {
48 const v = JSON.stringify(value);
49 if (check(v))
50 yield v;
51 }
52 else if (Array.isArray(value)) {
53 yield '[';
54 safeAdd(seen, value);
55 let first = true;
56 for (const v of value) {
57 if (!first)
58 yield ',';
59 else
60 first = false;
61 yield* jsonStringifyGenerator(v, seen);
62 }
63 seen.delete(value);
64 yield ']';
65 }
66 else if (value != null && typeof value === 'object') {
67 yield '{';
68 safeAdd(seen, value);
69 let first = true;
70 for (const [k, v] of Object.entries(value)) {
71 if (check(v)) {
72 const generator = jsonStringifyGenerator(v, seen);
73 const peek = await generator.next();
74 if (check(peek.value)) {
75 if (!first)
76 yield ',';
77 else
78 first = false;
79 yield `${JSON.stringify(k)}:`;
80 yield peek.value;
81 yield* generator;
82 }
83 }
84 }
85 seen.delete(value);
86 yield '}';
87 }
88 else {
89 yield check(value) ? JSON.stringify(value) : 'null';
90 }
91}
92/**
93 * @deprecated Change name to something more descriptive!?
94 */
95export function jsonStringifyStream(value) {
96 return asyncIterToStream(jsonStringifyGenerator(value));
97}
98export class JSONStringifyReadable extends ReadableStream {
99 constructor(value) {
100 let iterator;
101 super({
102 start() {
103 iterator = jsonStringifyGenerator(value)[Symbol.asyncIterator]();
104 },
105 async pull(controller) {
106 // console.log('stringify', controller.desiredSize)
107 const { value, done } = await iterator.next();
108 if (!done)
109 controller.enqueue(value);
110 else
111 controller.close();
112 },
113 async cancel(reason) {
114 var _a;
115 try {
116 await ((_a = iterator.throw) === null || _a === void 0 ? void 0 : _a.call(iterator, reason));
117 }
118 catch { }
119 },
120 });
121 }
122}
123//# sourceMappingURL=json-stringify.js.map
\No newline at end of file