diff --git a/package-lock.json b/package-lock.json index 040b68de9f..7a5313f6d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,8 @@ ], "dependencies": { "json-bigint": "^1.0.0", - "lossless-json": "^4.0.1" + "lossless-json": "^4.0.1", + "rimraf": "^6.0.1" }, "devDependencies": { "@faker-js/faker": "^7.6.0", @@ -3233,7 +3234,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -3250,7 +3250,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -3262,7 +3261,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -3273,14 +3271,12 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -3297,7 +3293,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -3312,7 +3307,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -3944,6 +3938,27 @@ "node": ">= 6.0.0" } }, + "node_modules/@mapbox/node-pre-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -3957,6 +3972,22 @@ "node": ">= 6" } }, + "node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -4249,7 +4280,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -8303,7 +8333,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -9193,8 +9222,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ecc-jsbn": { "version": "0.1.2", @@ -10333,7 +10361,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -10349,7 +10376,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -12120,8 +12146,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isobject": { "version": "3.0.1", @@ -15004,8 +15029,7 @@ "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" }, "node_modules/package-json/node_modules/@sindresorhus/is": { "version": "0.14.0", @@ -15267,7 +15291,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -17374,37 +17397,110 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "optional": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dependencies": { - "glob": "^7.1.3" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "optional": true, + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/rimraf/node_modules/lru-cache": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/rimraf/node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -18028,7 +18124,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -18040,7 +18135,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -18410,7 +18504,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -18457,7 +18550,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -20010,7 +20102,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -20085,7 +20176,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -20514,7 +20604,7 @@ }, "packages/bruno-electron": { "name": "bruno", - "version": "v1.26.0", + "version": "v1.26.1", "dependencies": { "@aws-sdk/credential-providers": "3.525.0", "@usebruno/common": "0.1.0", diff --git a/package.json b/package.json index 21f2e38313..0aa6750b4c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "jest": "^29.2.0", "pretty-quick": "^3.1.3", "randomstring": "^1.2.2", + "rimraf": "^6.0.1", "ts-jest": "^29.0.5" }, "scripts": { diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index 85f6c2da4a..af8cda247f 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -66,7 +66,9 @@ if (!SERVER_RENDERED) { 'bru.getVar(key)', 'bru.setVar(key,value)', 'bru.deleteVar(key)', - 'bru.setNextRequest(requestName)' + 'bru.setNextRequest(requestName)', + 'bru.getRequestVar(key)', + 'bru.sleep(ms)' ]; CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => { const cursor = editor.getCursor(); diff --git a/packages/bruno-app/src/components/SecuritySettings/JsSandboxModeModal/index.js b/packages/bruno-app/src/components/SecuritySettings/JsSandboxModeModal/index.js index 4e5ec72921..2f010f71ff 100644 --- a/packages/bruno-app/src/components/SecuritySettings/JsSandboxModeModal/index.js +++ b/packages/bruno-app/src/components/SecuritySettings/JsSandboxModeModal/index.js @@ -6,7 +6,7 @@ import Portal from 'components/Portal'; import Modal from 'components/Modal'; import StyledWrapper from './StyledWrapper'; -const JsSandboxModeModal = ({ collection, onClose }) => { +const JsSandboxModeModal = ({ collection }) => { const dispatch = useDispatch(); const [jsSandboxMode, setJsSandboxMode] = useState(collection?.securityConfig?.jsSandboxMode || 'safe'); @@ -22,7 +22,6 @@ const JsSandboxModeModal = ({ collection, onClose }) => { ) .then(() => { toast.success('Sandbox mode updated successfully'); - onClose(); }) .catch((err) => console.log(err) && toast.error('Failed to update sandbox mode')); }; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index dd0aaf72d6..054b4fbd46 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -374,6 +374,7 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS }); }; +// rename item export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getState) => { const state = getState(); const collection = findCollectionByUid(state.collections.collections, collectionUid); @@ -718,7 +719,7 @@ export const newHttpRequest = (params) => (dispatch, getState) => { const pathParams = parsePathParams(requestUrl); each(pathParams, (pathParm) => { pathParams.enabled = true; - pathParm.type = 'path' + pathParm.type = 'path'; }); const params = [...queryParams, ...pathParams]; diff --git a/packages/bruno-common/src/interpolate/index.spec.ts b/packages/bruno-common/src/interpolate/index.spec.ts index a1994d4731..adfdf54cd1 100644 --- a/packages/bruno-common/src/interpolate/index.spec.ts +++ b/packages/bruno-common/src/interpolate/index.spec.ts @@ -294,7 +294,7 @@ describe('interpolate - recursive', () => { const result = interpolate(inputString, inputObject); - expect(result).toBe('{{recursion2}}'); + expect(result).toBe('{{recursion3}}'); }); it('should replace repetead placeholders with 1 level of recursion with values from the object', () => { @@ -335,4 +335,22 @@ describe('interpolate - recursive', () => { expect(result).toBe(new Array(24).fill('repetead4').join(' ')); }); + + it('should replace mutiple interdependent variables in the same input string', () => { + const inputString = `{ + "x": "{{v2}} {{v1}}" + }`; + const inputObject = { + foo: 'bar', + v1: '{{foo}}', + v2: '{{bar}}', + bar: 'baz' + }; + + const result = interpolate(inputString, inputObject); + + expect(result).toBe(`{ + "x": "baz bar" + }`); + }); }); diff --git a/packages/bruno-common/src/interpolate/index.ts b/packages/bruno-common/src/interpolate/index.ts index d4bd7cb6b0..4a4092d88d 100644 --- a/packages/bruno-common/src/interpolate/index.ts +++ b/packages/bruno-common/src/interpolate/index.ts @@ -27,32 +27,41 @@ const interpolate = (str: string, obj: Record): string => { const replace = ( str: string, flattenedObj: Record, - visited = new Set(), + visited = new Set(), results = new Map() ): string => { - const patternRegex = /\{\{([^}]+)\}\}/g; + let resultStr = str; + let matchFound = true; - return str.replace(patternRegex, (match, placeholder) => { - const replacement = flattenedObj[placeholder]; + while (matchFound) { + const patternRegex = /\{\{([^}]+)\}\}/g; + matchFound = false; + resultStr = resultStr.replace(patternRegex, (match, placeholder) => { + const replacement = flattenedObj[placeholder]; - if (results.has(match)) { - return results.get(match); - } + if (results.has(match)) { + return results.get(match); + } + + if (patternRegex.test(replacement) && !visited.has(match)) { + visited.add(match); + const result = replace(replacement, flattenedObj, visited, results); + results.set(match, result); + + matchFound = true; + return result; + } - if (patternRegex.test(replacement) && !visited.has(match)) { visited.add(match); - const result = replace(replacement, flattenedObj, visited, results); + const result = replacement !== undefined ? replacement : match; results.set(match, result); + matchFound = true; return result; - } - - visited.add(match); - const result = replacement !== undefined ? replacement : match; - results.set(match, result); + }); + } - return result; - }); + return resultStr; }; export default interpolate; diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index 82453ec664..945c215599 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -13,7 +13,9 @@ const { browseFiles, createDirectory, searchForBruFiles, - sanitizeDirectoryName + sanitizeDirectoryName, + isWSLPath, + normalizeWslPath, } = require('../utils/filesystem'); const { openCollectionDialog } = require('../app/collections'); const { generateUidBasedOnHash, stringifyJson, safeParseJSON, safeStringifyJSON } = require('../utils/common'); @@ -326,6 +328,14 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection // rename item ipcMain.handle('renderer:rename-item', async (event, oldPath, newPath, newName) => { try { + // Normalize paths if they are WSL paths + if (isWSLPath(oldPath)) { + oldPath = normalizeWslPath(oldPath); + } + if (isWSLPath(newPath)) { + newPath = normalizeWslPath(newPath); + } + if (!fs.existsSync(oldPath)) { throw new Error(`path: ${oldPath} does not exist`); } diff --git a/packages/bruno-electron/src/utils/filesystem.js b/packages/bruno-electron/src/utils/filesystem.js index 8216bd9c92..752cb339c8 100644 --- a/packages/bruno-electron/src/utils/filesystem.js +++ b/packages/bruno-electron/src/utils/filesystem.js @@ -50,6 +50,18 @@ const normalizeAndResolvePath = (pathname) => { return path.resolve(pathname); }; +function isWSLPath(pathname) { + // Check if the path starts with the WSL prefix + // eg. "\\wsl.localhost\Ubuntu\home\user\bruno\collection\scripting\api\req\getHeaders.bru" + return pathname.startsWith('/wsl.localhost/') || pathname.startsWith('\\wsl.localhost\\'); +} + +function normalizeWslPath(pathname) { + // Replace the WSL path prefix and convert forward slashes to backslashes + // This is done to achieve WSL paths (linux style) to Windows UNC equivalent (Universal Naming Conversion) + return pathname.replace(/^\/wsl.localhost/, '\\\\wsl.localhost').replace(/\//g, '\\'); +} + const writeFile = async (pathname, content) => { try { fs.writeFileSync(pathname, content, { @@ -143,6 +155,8 @@ const searchForBruFiles = (dir) => { return searchForFiles(dir, '.bru'); }; +// const isW + const sanitizeDirectoryName = (name) => { return name.replace(/[<>:"/\\|?*\x00-\x1F]+/g, '-'); }; @@ -154,6 +168,8 @@ module.exports = { isFile, isDirectory, normalizeAndResolvePath, + isWSLPath, + normalizeWslPath, writeFile, writeBinaryFile, hasJsonExtension, diff --git a/packages/bruno-js/src/sandbox/quickjs/index.js b/packages/bruno-js/src/sandbox/quickjs/index.js index 5e568ee666..79ee2b8e81 100644 --- a/packages/bruno-js/src/sandbox/quickjs/index.js +++ b/packages/bruno-js/src/sandbox/quickjs/index.js @@ -21,11 +21,30 @@ const toNumber = (value) => { return Number.isInteger(num) ? parseInt(value, 10) : parseFloat(value); }; +const removeQuotes = (str) => { + if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) { + return str.slice(1, -1); + } + return str; +}; + const executeQuickJsVm = ({ script: externalScript, context: externalContext, scriptType = 'template-literal' }) => { + if (!externalScript?.length || typeof externalScript !== 'string') { + return externalScript; + } + externalScript = externalScript?.trim(); + if (!isNaN(Number(externalScript))) { return Number(externalScript); } + if (externalScript === 'true') return true; + if (externalScript === 'false') return false; + if (externalScript === 'null') return null; + if (externalScript === 'undefined') return undefined; + + externalScript = removeQuotes(externalScript); + const vm = QuickJSSyncContext; try { @@ -57,9 +76,22 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc }; const executeQuickJsVmAsync = async ({ script: externalScript, context: externalContext, collectionPath }) => { + if (!externalScript?.length || typeof externalScript !== 'string') { + return externalScript; + } + externalScript = externalScript?.trim(); + if (!isNaN(Number(externalScript))) { return toNumber(externalScript); } + + if (externalScript === 'true') return true; + if (externalScript === 'false') return false; + if (externalScript === 'null') return null; + if (externalScript === 'undefined') return undefined; + + externalScript = removeQuotes(externalScript); + try { const module = await newQuickJSWASMModule(); const vm = module.newContext(); diff --git a/packages/bruno-tests/collection/echo/echo xml parsed(self closing tags).bru b/packages/bruno-tests/collection/echo/echo xml parsed(self closing tags).bru new file mode 100644 index 0000000000..d337cebb38 --- /dev/null +++ b/packages/bruno-tests/collection/echo/echo xml parsed(self closing tags).bru @@ -0,0 +1,37 @@ +meta { + name: echo xml parsed(self closing tags) + type: http + seq: 6 +} + +post { + url: {{host}}/api/echo/xml-parsed + body: xml + auth: none +} + +body:xml { + + bruno + + +} + +assert { + res.status: eq 200 +} + +tests { + test("should return parsed xml", function() { + const data = res.getBody(); + expect(res.getBody()).to.eql({ + "hello": { + "world": [ + "bruno", + "" + ] + } + }); + }); + +} diff --git a/packages/bruno-tests/collection/scripting/js/data types - request vars.bru b/packages/bruno-tests/collection/scripting/js/data types - request vars.bru new file mode 100644 index 0000000000..3692c46cbf --- /dev/null +++ b/packages/bruno-tests/collection/scripting/js/data types - request vars.bru @@ -0,0 +1,68 @@ +meta { + name: data types - request vars + type: http + seq: 3 +} + +post { + url: {{host}}/api/echo/json + body: json + auth: none +} + +body:json { + { + "boolean": false, + "number": 1, + "string": "bruno", + "array": [1, 2, 3, 4, 5], + "object": { + "hello": "bruno" + }, + "null": null + } +} + +vars:pre-request { + number: 1 + boolean: false + undefined: undefined + null: null + string: foo +} + +assert { + req.body.boolean: isBoolean false + req.body.number: isNumber 1 + req.body.undefined: isUndefined undefined + req.body.string: isString bruno + req.body.null: isNull null + req.body.array: isArray + req.body.boolean: eq false + req.body.number: eq 1 + req.body.undefined: eq undefined + req.body.string: eq bruno + req.body.null: eq null +} + +tests { + test("boolean pre var", function() { + expect(bru.getRequestVar('boolean')).to.eql(false); + }); + + test("number pre var", function() { + expect(bru.getRequestVar('number')).to.eql(1); + }); + + test("null pre var", function() { + expect(bru.getRequestVar('null')).to.eql(null); + }); + + test("undefined pre var", function() { + expect(bru.getRequestVar('undefined')).to.eql(undefined); + }); + + test("string pre var", function() { + expect(bru.getRequestVar('string')).to.eql('foo'); + }); +}