mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-03 09:28:33 +00:00
Compare commits
4 Commits
fix/playwr
...
release/v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d9dfa239d | ||
|
|
b7be6aacce | ||
|
|
955d33f1fe | ||
|
|
f3c38400ff |
8
package-lock.json
generated
8
package-lock.json
generated
@@ -14235,9 +14235,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fast-json-format": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-format/-/fast-json-format-0.3.0.tgz",
|
||||
"integrity": "sha512-B95psGYXJ5XItmxLR6JFcQRQafDyfy8ecHiV/jWCJF9oCIA9/o+wt89cGW61D04xf07yCpIaevvCQbgeJ9w8lQ==",
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-format/-/fast-json-format-0.4.0.tgz",
|
||||
"integrity": "sha512-HEomBtr2fYaVX3iaRdcVLU7Qd3SQhCYvXlMMM9RNaihfIaj5bIC7ADqw/bAPSg/uyX6FIBPq69ioXq0B4Cb6eA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
@@ -26874,7 +26874,7 @@
|
||||
"dompurify": "^3.2.4",
|
||||
"escape-html": "^1.0.3",
|
||||
"fast-fuzzy": "^1.12.0",
|
||||
"fast-json-format": "~0.3.0",
|
||||
"fast-json-format": "~0.4.0",
|
||||
"file": "^0.2.2",
|
||||
"file-dialog": "^0.0.8",
|
||||
"file-saver": "^2.0.5",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"dompurify": "^3.2.4",
|
||||
"escape-html": "^1.0.3",
|
||||
"fast-fuzzy": "^1.12.0",
|
||||
"fast-json-format": "~0.3.0",
|
||||
"fast-json-format": "~0.4.0",
|
||||
"file": "^0.2.2",
|
||||
"file-dialog": "^0.0.8",
|
||||
"file-saver": "^2.0.5",
|
||||
|
||||
@@ -6,9 +6,9 @@ import { updateRequestGraphqlVariables } from 'providers/ReduxStore/slices/colle
|
||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { format, applyEdits } from 'jsonc-parser';
|
||||
import { IconWand } from '@tabler/icons';
|
||||
import toast from 'react-hot-toast';
|
||||
import { prettifyJsonString } from 'utils/common/index';
|
||||
|
||||
const GraphQLVariables = ({ variables, item, collection }) => {
|
||||
const dispatch = useDispatch();
|
||||
@@ -19,8 +19,7 @@ const GraphQLVariables = ({ variables, item, collection }) => {
|
||||
const onPrettify = () => {
|
||||
if (!variables) return;
|
||||
try {
|
||||
const edits = format(variables, undefined, { tabSize: 2, insertSpaces: true });
|
||||
const prettyVariables = applyEdits(variables, edits);
|
||||
const prettyVariables = prettifyJsonString(variables);
|
||||
dispatch(
|
||||
updateRequestGraphqlVariables({
|
||||
variables: prettyVariables,
|
||||
|
||||
@@ -12,9 +12,9 @@ import StyledWrapper from './StyledWrapper';
|
||||
import { IconSend, IconRefresh, IconWand, IconPlus, IconTrash, IconChevronDown, IconChevronUp } from '@tabler/icons';
|
||||
import ToolHint from 'components/ToolHint/index';
|
||||
import { toastError } from 'utils/common/error';
|
||||
import { format, applyEdits } from 'jsonc-parser';
|
||||
import toast from 'react-hot-toast'
|
||||
import { getAbsoluteFilePath } from 'utils/common/path';
|
||||
import { prettifyJsonString } from 'utils/common/index';
|
||||
|
||||
const SingleGrpcMessage = ({ message, item, collection, index, methodType, isCollapsed, onToggleCollapse, handleRun, canClientSendMultipleMessages }) => {
|
||||
const dispatch = useDispatch();
|
||||
@@ -130,8 +130,7 @@ const SingleGrpcMessage = ({ message, item, collection, index, methodType, isCol
|
||||
|
||||
const onPrettify = () => {
|
||||
try {
|
||||
const edits = format(content, undefined, { tabSize: 2, insertSpaces: true });
|
||||
const prettyBodyJson = applyEdits(content, edits);
|
||||
const prettyBodyJson = prettifyJsonString(content);
|
||||
|
||||
const currentMessages = [...(body.grpc || [])];
|
||||
currentMessages[index] = {
|
||||
|
||||
@@ -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 { format, applyEdits } from 'jsonc-parser';
|
||||
import { patternHasher } from '@usebruno/common/utils';
|
||||
|
||||
// a customized version of nanoid without using _ and -
|
||||
@@ -294,7 +295,7 @@ export const formatResponse = (data, dataBufferString, mode, filter, bufferThres
|
||||
}
|
||||
|
||||
try {
|
||||
return prettifyJsonString(rawData);
|
||||
return fastJsonFormat(rawData);
|
||||
} catch (error) {}
|
||||
|
||||
if (typeof data === 'string') {
|
||||
@@ -326,9 +327,11 @@ export const formatResponse = (data, dataBufferString, mode, filter, bufferThres
|
||||
|
||||
export const prettifyJsonString = (jsonDataString) => {
|
||||
if (typeof jsonDataString !== 'string') return jsonDataString;
|
||||
|
||||
try {
|
||||
const { hashed, restore } = patternHasher(jsonDataString);
|
||||
const formattedJsonDataStringHashed = fastJsonFormat(hashed);
|
||||
const edits = format(hashed, undefined, { tabSize: 2, insertSpaces: true });
|
||||
const formattedJsonDataStringHashed = applyEdits(hashed, edits);
|
||||
const formattedJsonDataString = restore(formattedJsonDataStringHashed);
|
||||
return formattedJsonDataString;
|
||||
} catch (error) {
|
||||
|
||||
@@ -218,16 +218,16 @@ describe('common utils', () => {
|
||||
});
|
||||
|
||||
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 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 ",
|
||||
"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",
|
||||
"escapedCharacters": "Line1\\nLine2\\tTabbed\"Quoted\" and 'single quoted' with 'code' style",
|
||||
"nestedObject": {
|
||||
"level1": {
|
||||
"level2": {
|
||||
@@ -280,7 +280,7 @@ describe('common utils', () => {
|
||||
"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 "
|
||||
"multiLineString": "This is a long text\\nthat spans multiple\\nlines with \`backticks\` 'quotes' and 'code' snippets "
|
||||
}`;
|
||||
expect(prettifyJsonString(input)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
@@ -29,4 +29,10 @@ describe('patternHasher', () => {
|
||||
expect(hashed).toMatchInlineSnapshot(`"$name.example.com"`);
|
||||
expect(restore(hashed)).toEqual(originalUrl);
|
||||
});
|
||||
|
||||
it('verify restoring duplicate hashes', () => {
|
||||
const originalJSON = `{"name":"{{name}}","x":"{{name}}", "y":"{{name}}"}`;
|
||||
const { hashed, restore } = patternHasher(originalJSON);
|
||||
expect(restore(hashed)).toEqual(originalJSON);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,7 +41,7 @@ export function patternHasher(input: string, pattern: string | RegExp = VARIABLE
|
||||
let clone = current;
|
||||
for (const hash in hashToOriginal) {
|
||||
const value = hashToOriginal[hash];
|
||||
clone = clone.replace(hash, value);
|
||||
clone = clone.replaceAll(hash, value);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"target": "ES6",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"lib": ["es2021"],
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react",
|
||||
"module": "ESNext",
|
||||
|
||||
@@ -13,6 +13,7 @@ post {
|
||||
body:json {
|
||||
{
|
||||
"bigint": 1736184243098437392,
|
||||
"unicode": ["\u4e00","\u4e8c","\u4e09"]
|
||||
"unicode": ["\u4e00","\u4e8c","\u4e09"],
|
||||
"forwardslashes": "\/url\/path\/"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ test.describe.serial('JSON Response Formatting', () => {
|
||||
await expect(responseBody).toContainText('一');
|
||||
await expect(responseBody).toContainText('二');
|
||||
await expect(responseBody).toContainText('三');
|
||||
|
||||
// The response should handle escaped forward slashes
|
||||
await expect(responseBody).toContainText('/url/path/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user