diff --git a/package.json b/package.json index ebe1af53f..2c46fdd2c 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "ts-jest": "^29.0.5" }, "scripts": { + "setup": "node ./scripts/setup.js", "dev": "concurrently --kill-others \"npm run dev:web\" \"npm run dev:electron\"", "dev:web": "npm run dev --workspace=packages/bruno-app", "build:web": "npm run build --workspace=packages/bruno-app", @@ -51,6 +52,6 @@ "prepare": "husky install" }, "overrides": { - "rollup":"3.29.5" + "rollup": "3.29.5" } } diff --git a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js index e9acd1f5c..b6b8d751d 100644 --- a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js +++ b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js @@ -20,14 +20,14 @@ const formatResponse = (data, mode, filter) => { } if (data === null) { - return data; + return 'null'; } if (mode.includes('json')) { let isValidJSON = false; try { - isValidJSON = typeof JSON.parse(JSON.stringify(data)) === 'object'; + isValidJSON = typeof JSON.parse(JSON.stringify(data)) === 'object' } catch (error) { console.log('Error parsing JSON: ', error.message); } diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js b/packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js index 77f469125..def88f2b6 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js @@ -191,7 +191,7 @@ export const globalEnvironmentsUpdateEvent = ({ globalEnvironmentVariables }) => // update existing values variables = variables?.map?.(variable => ({ ...variable, - value: stringifyIfNot(globalEnvironmentVariables?.[variable?.name]) + value: globalEnvironmentVariables?.[variable?.name] })); // add new env values @@ -201,7 +201,7 @@ export const globalEnvironmentsUpdateEvent = ({ globalEnvironmentVariables }) => variables.push({ uid: uuid(), name: key, - value: stringifyIfNot(value), + value, type: 'text', secret: false, enabled: true diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index 3a691e53f..d770c60a3 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -797,7 +797,7 @@ export const getGlobalEnvironmentVariables = ({ globalEnvironments, activeGlobal const environment = globalEnvironments?.find(env => env?.uid === activeGlobalEnvironmentUid); if (environment) { each(environment.variables, (variable) => { - if (variable.name && variable.value && variable.enabled) { + if (variable.name && variable.enabled) { variables[variable.name] = variable.value; } }); diff --git a/packages/bruno-app/src/utils/curl/curl-to-json.js b/packages/bruno-app/src/utils/curl/curl-to-json.js index 48c33bb0a..c1398ab14 100644 --- a/packages/bruno-app/src/utils/curl/curl-to-json.js +++ b/packages/bruno-app/src/utils/curl/curl-to-json.js @@ -57,7 +57,7 @@ function getDataString(request) { console.error('Failed to parse JSON data:', error); return { data: request.data.toString() }; } - } else if (contentType && contentType.includes('application/xml')) { + } else if (contentType && (contentType.includes('application/xml') || contentType.includes('text/plain'))) { return { data: request.data }; } @@ -174,14 +174,14 @@ const curlToJson = (curlCommand) => { } if (request.auth) { - if(request.auth.mode === 'basic'){ + if (request.auth.mode === 'basic') { requestJson.auth = { mode: 'basic', basic: { username: repr(request.auth.basic?.username), password: repr(request.auth.basic?.password) } - } + }; } } diff --git a/packages/bruno-app/src/utils/importers/common.js b/packages/bruno-app/src/utils/importers/common.js index c99048419..88c4c7872 100644 --- a/packages/bruno-app/src/utils/importers/common.js +++ b/packages/bruno-app/src/utils/importers/common.js @@ -79,9 +79,9 @@ export const transformItemsInCollection = (collection) => { // from 5 feb 2024, multipartFormData needs to have a type // this was introduced when we added support for file uploads // below logic is to make older collection exports backward compatible - let multipartFormData = _.get(item, 'request.body.multipartForm'); + let multipartFormData = get(item, 'request.body.multipartForm'); if (multipartFormData) { - _.each(multipartFormData, (form) => { + each(multipartFormData, (form) => { if (!form.type) { form.type = 'text'; } diff --git a/packages/bruno-cli/src/runner/prepare-request.js b/packages/bruno-cli/src/runner/prepare-request.js index 21cf17bd1..0ed866760 100644 --- a/packages/bruno-cli/src/runner/prepare-request.js +++ b/packages/bruno-cli/src/runner/prepare-request.js @@ -136,8 +136,7 @@ const prepareRequest = (item = {}, collection = {}) => { if (request.body.mode === 'multipartForm') { axiosRequest.headers['content-type'] = 'multipart/form-data'; const enabledParams = filter(request.body.multipartForm, (p) => p.enabled); - const collectionPath = process.cwd(); - axiosRequest.data = createFormData(enabledParams, collectionPath); + axiosRequest.data = enabledParams; } if (request.body.mode === 'graphql') { diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index d1ff7c3f9..898324892 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -349,10 +349,10 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection // rename item ipcMain.handle('renderer:rename-item', async (event, oldPath, newPath, newName) => { const tempDir = path.join(os.tmpdir(), `temp-folder-${Date.now()}`); - const parentDir = path.dirname(oldPath); - const isWindowsOSAndNotWSLAndItemHasSubDirectories = isWindowsOS() && !isWSLPath(oldPath) && hasSubDirectories(oldPath); - let parentDirUnwatched = false; - let parentDirRewatched = false; + // const parentDir = path.dirname(oldPath); + const isWindowsOSAndNotWSLAndItemHasSubDirectories = isDirectory(oldPath) && isWindowsOS() && !isWSLPath(oldPath) && hasSubDirectories(oldPath); + // let parentDirUnwatched = false; + // let parentDirRewatched = false; try { // Normalize paths if they are WSL paths @@ -376,8 +376,8 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection moveRequestUid(bruFile, newBruFilePath); } - watcher.unlinkItemPathInWatcher(parentDir); - parentDirUnwatched = true; + // watcher.unlinkItemPathInWatcher(parentDir); + // parentDirUnwatched = true; /** * If it is windows OS @@ -396,8 +396,8 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } else { await fs.renameSync(oldPath, newPath); } - watcher.addItemPathInWatcher(parentDir); - parentDirRewatched = true; + // watcher.addItemPathInWatcher(parentDir); + // parentDirRewatched = true; return newPath; } @@ -424,9 +424,9 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } catch (error) { // in case an error occurs during the rename file operations after unlinking the parent dir // and the rewatch fails, we need to add it back to watcher - if (parentDirUnwatched && !parentDirRewatched) { - watcher.addItemPathInWatcher(parentDir); - } + // if (parentDirUnwatched && !parentDirRewatched) { + // watcher.addItemPathInWatcher(parentDir); + // } // in case the rename file operations fails, and we see that the temp dir exists // and the old path does not exist, we need to restore the data from the temp dir to the old path diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 9e37c8289..84f49d07b 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -365,11 +365,15 @@ const parseDataFromResponse = (response, disableParsingResponseJson = false) => try { // Filter out ZWNBSP character // https://gist.github.com/antic183/619f42b559b78028d1fe9e7ae8a1352d + + // If the response is a string and starts and ends with double quotes, it's a stringified JSON and should not be parsed data = data.replace(/^\uFEFF/, ''); - if (!disableParsingResponseJson) { + if ( !disableParsingResponseJson && ! (typeof data === 'string' && data.startsWith("\"") && data.endsWith("\""))) { data = JSON.parse(data); } - } catch { } + } catch { + console.log('Failed to parse response data as JSON'); + } return { data, dataBuffer }; }; diff --git a/packages/bruno-tests/collection/echo/echo multipart.bru b/packages/bruno-tests/collection/echo/echo multipart.bru index 1edb2ca8a..09176d74f 100644 --- a/packages/bruno-tests/collection/echo/echo multipart.bru +++ b/packages/bruno-tests/collection/echo/echo multipart.bru @@ -11,6 +11,7 @@ post { } body:multipart-form { + foo: {"bar":"baz"} @contentType(application/json--test) form-data-key: {{form-data-key}} form-data-stringified-object: {{form-data-stringified-object}} file: @file(bruno.png) @@ -19,6 +20,7 @@ body:multipart-form { assert { res.body: contains form-data-value res.body: contains {"foo":123} + res.body: contains Content-Type: application/json--test } script:pre-request { diff --git a/packages/bruno-tests/collection/multipart/mixed-content-types.bru b/packages/bruno-tests/collection/multipart/mixed-content-types.bru deleted file mode 100644 index 29ed04ba1..000000000 --- a/packages/bruno-tests/collection/multipart/mixed-content-types.bru +++ /dev/null @@ -1,24 +0,0 @@ -meta { - name: mixed-content-types - type: http - seq: 1 -} - -post { - url: {{host}}/api/multipart/mixed-content-types - body: multipartForm - auth: none -} - -body:multipart-form { - param1: test - param2: {"test":"i am json"} @contentType(application/json) - param3: @file(multipart/small.png) -} - -assert { - res.status: eq 200 - res.body.find(p=>p.name === 'param1').contentType: isUndefined - res.body.find(p=>p.name === 'param2').contentType: eq application/json - res.body.find(p=>p.name === 'param3').contentType: eq image/png -} diff --git a/scripts/setup.js b/scripts/setup.js new file mode 100644 index 000000000..47d679098 --- /dev/null +++ b/scripts/setup.js @@ -0,0 +1,95 @@ +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +const icons = { + clean: '๐Ÿงน', + delete: '๐Ÿ—‘๏ธ', + install: '๐Ÿ“ฆ', + build: '๐Ÿ”จ', + success: 'โœ…', + error: 'โŒ', + working: 'โšก' +}; + +const execCommand = (command, description) => { + try { + console.log(`\n${icons.working} ${description}...`); + execSync(command, { stdio: 'inherit' }); + console.log(`${icons.success} ${description} completed`); + } catch (error) { + console.error(`${icons.error} ${description} failed`); + throw error; + } +}; + +const glob = function (startPath, pattern) { + let results = []; + + // Ensure start path exists + if (!fs.existsSync(startPath)) { + return results; + } + + const files = fs.readdirSync(startPath); + for (const file of files) { + const filename = path.join(startPath, file); + const stat = fs.lstatSync(filename); + + // If directory, recurse into it + if (stat.isDirectory()) { + // Skip node_modules recursion to avoid unnecessary deep scanning + if (file === 'node_modules') { + if (file === pattern) { + results.push(filename); + } + continue; + } + results = results.concat(glob(filename, pattern)); + } + + // If file matches pattern, add to results + if (file === pattern) { + results.push(filename); + } + } + + return results; +}; + +async function setup() { + try { + // Clean up node_modules (if exists) + console.log(`\n${icons.clean} Cleaning up node_modules directories...`); + const nodeModulesPaths = glob('.', 'node_modules'); + for (const dir of nodeModulesPaths) { + console.log(`${icons.delete} Removing ${dir}`); + fs.rmSync(dir, { recursive: true, force: true }); + } + + // Install dependencies + execCommand('npm i --legacy-peer-deps', 'Installing dependencies'); + + // Build packages + execCommand('npm run build:graphql-docs', 'Building graphql-docs'); + execCommand('npm run build:bruno-query', 'Building bruno-query'); + execCommand('npm run build:bruno-common', 'Building bruno-common'); + + // Bundle JS sandbox libraries + execCommand( + 'npm run sandbox:bundle-libraries --workspace=packages/bruno-js', + 'Bundling JS sandbox libraries' + ); + + console.log(`\n${icons.success} Setup completed successfully!\n`); + } catch (error) { + console.error(`\n${icons.error} Setup failed:`); + console.error(error); + process.exit(1); + } +} + +setup().catch(error => { + console.error(error); + process.exit(1); +});