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;
}