fix: handle prettifying json data with bruno variables (#6038)

This commit is contained in:
lohit
2025-11-07 21:07:30 +05:30
committed by GitHub
parent 68b2625259
commit 57c08350b6
6 changed files with 121 additions and 8 deletions

View File

@@ -8,7 +8,7 @@ import { humanizeRequestBodyMode } from 'utils/collections';
import StyledWrapper from './StyledWrapper';
import { updateRequestBody } from 'providers/ReduxStore/slices/collections/index';
import { toastError } from 'utils/common/error';
import fastJsonFormat from 'fast-json-format';
import { prettifyJsonString } from 'utils/common/index';
import xmlFormat from 'xml-formatter';
const RequestBodyMode = ({ item, collection }) => {
@@ -39,7 +39,7 @@ const RequestBodyMode = ({ item, collection }) => {
const onPrettify = () => {
if (body?.json && bodyMode === 'json') {
try {
const prettyBodyJson = fastJsonFormat(body.json);
const prettyBodyJson = prettifyJsonString(body.json);
dispatch(
updateRequestBody({
content: prettyBodyJson,

View File

@@ -10,7 +10,7 @@ import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { autoDetectLang } from 'utils/codemirror/lang-detect';
import { toastError } from 'utils/common/error';
import fastJsonFormat from 'fast-json-format';
import { prettifyJsonString } from 'utils/common/index';
import xmlFormat from 'xml-formatter';
import WSRequestBodyMode from '../BodyMode/index';
@@ -105,7 +105,7 @@ export const SingleWSMessage = ({
const onPrettify = () => {
if (codeType === 'json') {
try {
const prettyBodyJson = fastJsonFormat(content);
const prettyBodyJson = prettifyJsonString(content);
const currentMessages = [...(body.ws || [])];
currentMessages[index] = {
...currentMessages[index],

View File

@@ -2,6 +2,7 @@ import { customAlphabet } from 'nanoid';
import xmlFormat from 'xml-formatter';
import { JSONPath } from 'jsonpath-plus';
import fastJsonFormat from 'fast-json-format';
import { patternHasher } from '@usebruno/common/utils';
// a customized version of nanoid without using _ and -
export const uuid = () => {
@@ -293,7 +294,7 @@ export const formatResponse = (data, dataBufferString, mode, filter, bufferThres
}
try {
return fastJsonFormat(rawData);
return prettifyJsonString(rawData);
} catch (error) {}
if (typeof data === 'string') {
@@ -322,3 +323,17 @@ export const formatResponse = (data, dataBufferString, mode, filter, bufferThres
return safeStringifyJSON(data, !isVeryLargeResponse);
};
export const prettifyJsonString = (jsonDataString) => {
if (typeof jsonDataString !== 'string') return jsonDataString;
try {
const { hashed, restore } = patternHasher(jsonDataString);
const formattedJsonDataStringHashed = fastJsonFormat(hashed);
const formattedJsonDataString = restore(formattedJsonDataStringHashed);
return formattedJsonDataString;
} catch (error) {
console.log('error formatting json data!');
console.error(error);
}
return jsonDataString;
};

View File

@@ -6,7 +6,8 @@ import {
humanizeDate,
relativeDate,
getContentType,
formatSize
formatSize,
prettifyJsonString
} from './index';
describe('common utils', () => {
@@ -191,4 +192,97 @@ describe('common utils', () => {
expect(formatSize(NaN)).toBe('0B');
});
});
describe('prettifyJsonString', () => {
test('should return non-string inputs unchanged', () => {
expect(prettifyJsonString(null)).toBe(null);
expect(prettifyJsonString(undefined)).toBe(undefined);
expect(prettifyJsonString(123)).toBe(123);
expect(prettifyJsonString([])).toEqual([]);
expect(prettifyJsonString({})).toEqual({});
expect(prettifyJsonString(true)).toBe(true);
});
test('should format valid JSON without Bruno variables', () => {
const input = '{"name":"John","age":30}';
const expected = `{\n "name": "John",\n "age": 30\n}`;
console.log(prettifyJsonString(input));
expect(prettifyJsonString(input)).toBe(expected);
});
test('should format valid JSON with Bruno variables', () => {
const input = '{"name": {{userName}}}';
const expected = `{\n "name": {{userName}}\n}`;
console.log(prettifyJsonString(input));
expect(prettifyJsonString(input)).toBe(expected);
});
test('should format complex json string', () => {
const input = `{"id": 123456789123456789123456789,"name": "Test 'JSON' Data with "quotes" — Pretty Print ","active": true,"price": 199.9999999,"decimals": 1.00,"nullValue": null,"unicodeText": "こんにちは世界 ","escapedCharacters": "Line1\nLine2\tTabbed\"Quoted\" and 'single quoted' with 'code' style","nestedObject": { "level1": { "level2": { "emptyArray": [], "specialChars": "@#$%^&*()_+-=[]{}|;':,./<>?~", "booleanValues": [ true, false, true ], "numbers": [ 0, -1, 1.23e10, 3.1415926535 ] } }},"mixedArray": [ "string with 'apostrophe'", 42, false, null, { "innerObj": { "keyWithQuotes": "value containing \`backticks\` and 'single quotes'", "nestedArray": [ { "a": "O'Reilly" }{ "b": "'inline code'" }, [ "deep", "array", { "c": "contains 'quotes'" } ] ] } }],"nonStringVariable": {{nonStringVar}},"withBrunoVariable": "{{string}} '{{with}}' "{{variety}}" of '{{variables}}'","dateExample": "2025-11-07T12:34:56Z","regexExample": "^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$","urls": { "website": "https://example.com?param='value'&flag='true'", "escapedURL": "https:\/\/escaped-url.com\/path\?q='search'\&debug='on'"},"multiLineString": "This is a long text\nthat spans multiple\nlines with \`backticks\` 'quotes' and 'code' snippets "}`;
const expectedOutput = `{
"id": 123456789123456789123456789,
"name": "Test 'JSON' Data with "quotes" — Pretty Print ",
"active": true,
"price": 199.9999999,
"decimals": 1.00,
"nullValue": null,
"unicodeText": "こんにちは世界 ",
"escapedCharacters": "Line1\nLine2\tTabbed\"Quoted\" and 'single quoted' with 'code' style",
"nestedObject": {
"level1": {
"level2": {
"emptyArray": [],
"specialChars": "@#$%^&*()_+-=[]{}|;':,./<>?~",
"booleanValues": [
true,
false,
true
],
"numbers": [
0,
-1,
1.23e10,
3.1415926535
]
}
}
},
"mixedArray": [
"string with 'apostrophe'",
42,
false,
null,
{
"innerObj": {
"keyWithQuotes": "value containing \`backticks\` and 'single quotes'",
"nestedArray": [
{
"a": "O'Reilly"
}{
"b": "'inline code'"
},
[
"deep",
"array",
{
"c": "contains 'quotes'"
}
]
]
}
}
],
"nonStringVariable": {{nonStringVar}},
"withBrunoVariable": "{{string}} '{{with}}' "{{variety}}" of '{{variables}}'",
"dateExample": "2025-11-07T12:34:56Z",
"regexExample": "^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$",
"urls": {
"website": "https://example.com?param='value'&flag='true'",
"escapedURL": "https:\/\/escaped-url.com\/path\?q='search'\&debug='on'"
},
"multiLineString": "This is a long text\nthat spans multiple\nlines with \`backticks\` 'quotes' and 'code' snippets "
}`;
expect(prettifyJsonString(input)).toBe(expectedOutput);
});
});
});

View File

@@ -1,6 +1,6 @@
import { forOwn } from 'lodash';
import curlToJson from './curl-to-json';
import fastJsonFormat from 'fast-json-format';
import { prettifyJsonString } from 'utils/common/index';
export const getRequestFromCurlCommand = (curlCommand, requestType = 'http-request') => {
const parseFormData = (parsedBody) => {
@@ -67,7 +67,7 @@ export const getRequestFromCurlCommand = (curlCommand, requestType = 'http-reque
body.file = parsedBody;
}else if (contentType.includes('application/json')) {
body.mode = 'json';
body.json = fastJsonFormat(parsedBody);
body.json = prettifyJsonString(parsedBody);
} else if (contentType.includes('xml')) {
body.mode = 'xml';
body.xml = parsedBody;

View File

@@ -7,3 +7,7 @@ export {
export {
buildFormUrlEncodedPayload
} from './form-data';
export {
patternHasher
} from './template-hasher';