diff --git a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js index 78993a413..688a20e9b 100644 --- a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js +++ b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js @@ -80,7 +80,11 @@ const QueryResult = ({ item, collection, data, dataBuffer, width, disableRunEven const contentType = getContentType(headers); const mode = getCodeMirrorModeBasedOnContentType(contentType, data); const [filter, setFilter] = useState(null); - const formattedData = formatResponse(data, dataBuffer, getEncoding(headers), mode, filter); + const responseEncoding = getEncoding(headers); + const formattedData = useMemo( + () => formatResponse(data, dataBuffer, responseEncoding, mode, filter), + [data, dataBuffer, responseEncoding, mode, filter] + ); const { displayedTheme } = useTheme(); const debouncedResultFilterOnChange = debounce((e) => { diff --git a/packages/bruno-app/src/utils/common/formatJson.js b/packages/bruno-app/src/utils/common/formatJson.js new file mode 100644 index 000000000..5da6d1e5f --- /dev/null +++ b/packages/bruno-app/src/utils/common/formatJson.js @@ -0,0 +1,83 @@ +/** + * Credits to + * - https://github.com/zaach/jsonlint/blob/master/lib/formatter.js + * which is again copied from + * - https://github.com/umbrae/jsonlintdotcom/blob/master/c/js/jsl.format.js + * both under MIT license. + **/ + + +/** + * Provide json reformatting in a character-by-character approach, so that even invalid JSON may be reformatted (to the best of its ability). + * + **/ +export default function(json, indentChars) { + var i = 0, + il = 0, + tab = typeof indentChars !== 'undefined' ? indentChars : ' ', + newJson = '', + indentLevel = 0, + inString = false, + currentChar = null; + + for (i = 0, il = json.length; i < il; i += 1) { + currentChar = json.charAt(i); + + switch (currentChar) { + case '{': + case '[': + if (!inString) { + newJson += currentChar + '\n' + repeat(tab, indentLevel + 1); + indentLevel += 1; + } else { + newJson += currentChar; + } + break; + case '}': + case ']': + if (!inString) { + indentLevel -= 1; + newJson += '\n' + repeat(tab, indentLevel) + currentChar; + } else { + newJson += currentChar; + } + break; + case ',': + if (!inString) { + newJson += ',\n' + repeat(tab, indentLevel); + } else { + newJson += currentChar; + } + break; + case ':': + if (!inString) { + newJson += ': '; + } else { + newJson += currentChar; + } + break; + case ' ': + case '\n': + case '\t': + if (inString) { + newJson += currentChar; + } + break; + case '"': + if (i > 0 && json.charAt(i - 1) !== '\\') { + inString = !inString; + } + newJson += currentChar; + break; + default: + newJson += currentChar; + break; + } + } + + return newJson; +} + +function repeat(s, count) { + return new Array(count + 1).join(s); +} diff --git a/packages/bruno-app/src/utils/common/index.js b/packages/bruno-app/src/utils/common/index.js index 14fd8805a..76fa9aad8 100644 --- a/packages/bruno-app/src/utils/common/index.js +++ b/packages/bruno-app/src/utils/common/index.js @@ -1,6 +1,7 @@ import { customAlphabet } from 'nanoid'; import xmlFormat from 'xml-formatter'; -import { format as jsoncFormat, applyEdits as jsoncApplyEdits } from 'jsonc-parser'; + +import formatJson from 'utils/common/formatJson'; // a customized version of nanoid without using _ and - export const uuid = () => { @@ -28,11 +29,16 @@ export const waitForNextTick = () => { }; export const prettifyJson = (doc) => { - return jsoncApplyEdits( - doc, - jsoncFormat(doc, null, {insertSpaces: true, tabSize: 2}) - ); -} + // Format only the first 5MiB of the doc/JSON-string, + // this is to prevent bigger responses from blocking the thread + // and making the UI unresponsive. + // TODO: Implement UI to allow users to format whole JSON on-demand + const maxFormatLegth = 1048576 * 5; // 2 ^ 20 * 5 + const truncatedDoc = doc.substr(0, maxFormatLegth); + const restOfDoc = doc.substr(maxFormatLegth, doc.length); + const res = formatJson(truncatedDoc) + restOfDoc; + return res; +}; export const safeParseJSON = (str) => { if (!str || !str.length || typeof str !== 'string') {