function batchFormat()

in ts/webui/src/static/json_util.ts [25:129]


function batchFormat(
    objects: any[],
    curIndent: string,
    indent: string,
    width: number,
    keyOrKeys?: string | string[]
): string[] {
    let keys: string[]; // dict key as prefix string
    if (keyOrKeys === undefined) {
        keys = objects.map(() => '');
    } else if (typeof keyOrKeys === 'string') {
        keys = objects.map(() => `"${keyOrKeys}": `);
    } else {
        keys = keyOrKeys.map(k => `"${k}": `);
    }

    // try to collapse all
    const lines = objects.map((obj, i) => keys[i] + stringifySingleLine(obj));

    // null values don't affect hierarchy detection
    const nonNull = objects.filter(obj => obj !== null);
    if (nonNull.length === 0) {
        return lines;
    }

    const hasNested = nonNull.some(obj => detectNested(obj));

    if (!hasNested && lines.every(line => line.length + curIndent.length < width)) {
        return lines;
    }

    if (Array.isArray(nonNull[0])) {
        // objects are arrays, format all items in one batch
        const elements = batchFormat(concat(nonNull), curIndent + indent, indent, width);
        const iter = elements[Symbol.iterator]();
        return objects.map((obj, i) => {
            if (obj === null) {
                return keys[i] + 'null';
            } else {
                return (
                    keys[i] +
                    createBlock(
                        curIndent,
                        indent,
                        '[]',
                        obj.map(() => iter.next().value)
                    )
                );
            }
        });
    }

    if (typeof nonNull[0] === 'object') {
        // objects are dicts, format values in one batch if they have similar keys
        const values = concat(nonNull.map(obj => Object.values(obj)));
        const childrenKeys = concat(nonNull.map(obj => Object.keys(obj)));
        if (detectBatch(values)) {
            // these objects look like TypeScript style `Map` or `Record`, where the values have same "type"
            const elements = batchFormat(values, curIndent + indent, indent, width, childrenKeys);
            const iter = elements[Symbol.iterator]();
            return objects.map((obj, i) => {
                if (obj === null) {
                    return keys[i] + 'null';
                } else {
                    return (
                        keys[i] +
                        createBlock(
                            curIndent,
                            indent,
                            '{}',
                            Object.keys(obj).map(() => iter.next().value)
                        )
                    );
                }
            });
        } else {
            // these objects look like class instances, so we will try to group their fields
            const uniqueKeys = new Set(childrenKeys);
            const iters = new Map();
            for (const key of uniqueKeys) {
                const fields = nonNull.map(obj => obj[key]).filter(v => v !== undefined);
                let elements;
                if (detectBatch(fields)) {
                    // look like same field of class instances
                    elements = batchFormat(fields, curIndent + indent, indent, width, key);
                } else {
                    // no idea what these are, fallback to format them independently
                    elements = fields.map(field => batchFormat([field], curIndent + indent, indent, width, key));
                }
                iters.set(key, elements[Symbol.iterator]());
            }
            return objects.map((obj, i) => {
                if (obj === null) {
                    return keys[i] + 'null';
                } else {
                    const elements = Object.keys(obj).map(key => iters.get(key).next().value);
                    return keys[i] + createBlock(curIndent, indent, '{}', elements);
                }
            });
        }
    }

    // objects are primitive, impossible to break lines although they are too long
    return lines;
}