diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
index 22872cd46..c0762a441 100644
--- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
@@ -5,10 +5,20 @@ const Wrapper = styled.div`
width: 100%;
border-collapse: collapse;
font-weight: 600;
+ table-layout: fixed;
thead,
td {
border: 1px solid ${(props) => props.theme.collection.environment.settings.gridBorder};
+ padding: 4px 10px;
+
+ &:nth-child(1) {
+ width: 30%;
+ }
+
+ &:nth-child(3) {
+ width: 70px;
+ }
}
thead {
@@ -16,7 +26,7 @@ const Wrapper = styled.div`
font-size: 0.8125rem;
user-select: none;
}
- td {
+ thead td {
padding: 6px 10px;
}
}
diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js
index e3ad6e080..b50c8de6a 100644
--- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js
+++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js
@@ -2,13 +2,16 @@ import React, { useReducer } from 'react';
import toast from 'react-hot-toast';
import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
+import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
import { saveEnvironment } from 'providers/ReduxStore/slices/collections/actions';
import reducer from './reducer';
+import SingleLineEditor from 'components/SingleLineEditor';
import StyledWrapper from './StyledWrapper';
const EnvironmentVariables = ({ environment, collection }) => {
const dispatch = useDispatch();
+ const { storedTheme } = useTheme();
const [state, reducerDispatch] = useReducer(reducer, { hasChanges: false, variables: environment.variables || [] });
const { variables, hasChanges } = state;
@@ -86,15 +89,11 @@ const EnvironmentVariables = ({ environment, collection }) => {
/>
- handleVarChange(e, variable, 'value')}
+ theme={storedTheme}
+ onChange={(newValue) => handleVarChange({ target: { value: newValue } }, variable, 'value')}
+ collection={collection}
/>
|
diff --git a/packages/bruno-app/src/components/Modal/StyledWrapper.js b/packages/bruno-app/src/components/Modal/StyledWrapper.js
index 583bfe2ec..f0cb79353 100644
--- a/packages/bruno-app/src/components/Modal/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Modal/StyledWrapper.js
@@ -19,7 +19,7 @@ const Wrapper = styled.div`
align-items: flex-start;
justify-content: center;
overflow-y: auto;
- z-index: 1003;
+ z-index: 10;
}
.bruno-modal-card {
@@ -28,7 +28,7 @@ const Wrapper = styled.div`
background: var(--color-background-top);
border-radius: var(--border-radius);
position: relative;
- z-index: 1003;
+ z-index: 10;
max-width: calc(100% - var(--spacing-base-unit));
box-shadow: var(--box-shadow-base);
display: flex;
diff --git a/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js
index fbd05bb53..c63a0f2a1 100644
--- a/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js
+++ b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js
@@ -19,6 +19,7 @@ const StyledWrapper = styled.div`
.CodeMirror-scroll {
overflow: hidden !important;
+ padding-bottom: 50px !important;
}
.CodeMirror-hscrollbar {
diff --git a/packages/bruno-app/src/components/SingleLineEditor/index.js b/packages/bruno-app/src/components/SingleLineEditor/index.js
index 5925b598e..eef157ff9 100644
--- a/packages/bruno-app/src/components/SingleLineEditor/index.js
+++ b/packages/bruno-app/src/components/SingleLineEditor/index.js
@@ -31,6 +31,7 @@ class SingleLineEditor extends Component {
brunoVarInfo: {
variables: getAllVariables(this.props.collection)
},
+ scrollbarStyle: null,
extraKeys: {
Enter: () => {
if (this.props.onRun) {
diff --git a/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js b/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js
index b56cea098..3707359f2 100644
--- a/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js
+++ b/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js
@@ -1,5 +1,6 @@
import React from 'react';
import forOwn from 'lodash/forOwn';
+import isObject from 'lodash/isObject';
import cloneDeep from 'lodash/cloneDeep';
import { uuid } from 'utils/common';
import StyledWrapper from './StyledWrapper';
@@ -15,6 +16,14 @@ const VariablesTable = ({ variables, collectionVariables }) => {
});
});
+ const getValueToDisplay = (value) => {
+ if (value === undefined) {
+ return '';
+ }
+
+ return isObject(value) ? JSON.stringify(value) : value;
+ };
+
return (
@@ -24,7 +33,9 @@ const VariablesTable = ({ variables, collectionVariables }) => {
return (
{variable.name}
- {variable.value}
+
+ {getValueToDisplay(variable.value)}
+
);
})
@@ -38,7 +49,9 @@ const VariablesTable = ({ variables, collectionVariables }) => {
return (
{variable.name}
- {variable.value}
+
+ {getValueToDisplay(variable.value)}
+
);
})
diff --git a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
index 1f3c02c6f..858682e82 100644
--- a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
+++ b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
@@ -8,6 +8,7 @@ import {
collectionUnlinkDirectoryEvent,
collectionUnlinkEnvFileEvent,
scriptEnvironmentUpdateEvent,
+ processEnvUpdateEvent,
collectionRenamedEvent,
runRequestEvent,
runFolderEvent
@@ -97,6 +98,10 @@ const useCollectionTreeSync = () => {
dispatch(scriptEnvironmentUpdateEvent(val));
};
+ const _processEnvUpdate = (val) => {
+ dispatch(processEnvUpdateEvent(val));
+ };
+
const _collectionRenamed = (val) => {
dispatch(collectionRenamedEvent(val));
};
@@ -119,7 +124,8 @@ const useCollectionTreeSync = () => {
const removeListener6 = ipcRenderer.on('main:collection-renamed', _collectionRenamed);
const removeListener7 = ipcRenderer.on('main:run-folder-event', _runFolderEvent);
const removeListener8 = ipcRenderer.on('main:run-request-event', _runRequestEvent);
- const removeListener9 = ipcRenderer.on('main:console-log', (val) => {
+ const removeListener9 = ipcRenderer.on('main:process-env-update', _processEnvUpdate);
+ const removeListener10 = ipcRenderer.on('main:console-log', (val) => {
console[val.type](...val.args);
});
@@ -133,6 +139,7 @@ const useCollectionTreeSync = () => {
removeListener7();
removeListener8();
removeListener9();
+ removeListener10();
};
}, [isElectron]);
};
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
index c12b81eed..e1137aae7 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
@@ -177,6 +177,14 @@ export const collectionsSlice = createSlice({
collection.collectionVariables = collectionVariables;
}
},
+ processEnvUpdateEvent: (state, action) => {
+ const { collectionUid, processEnvVariables } = action.payload;
+ const collection = findCollectionByUid(state.collections, collectionUid);
+
+ if (collection) {
+ collection.processEnvVariables = processEnvVariables;
+ }
+ },
requestCancelled: (state, action) => {
const { itemUid, collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
@@ -1158,6 +1166,7 @@ export const {
renameItem,
cloneItem,
scriptEnvironmentUpdateEvent,
+ processEnvUpdateEvent,
requestCancelled,
responseReceived,
saveRequest,
diff --git a/packages/bruno-app/src/styles/_buttons.scss b/packages/bruno-app/src/styles/_buttons.scss
index 8b1378917..e69de29bb 100644
--- a/packages/bruno-app/src/styles/_buttons.scss
+++ b/packages/bruno-app/src/styles/_buttons.scss
@@ -1 +0,0 @@
-
diff --git a/packages/bruno-app/src/styles/app.scss b/packages/bruno-app/src/styles/app.scss
index 64423a4bb..46e81fc09 100644
--- a/packages/bruno-app/src/styles/app.scss
+++ b/packages/bruno-app/src/styles/app.scss
@@ -1 +1 @@
-@import "buttons";
+@import 'buttons';
diff --git a/packages/bruno-app/src/styles/globals.css b/packages/bruno-app/src/styles/globals.css
index 69f95ddcb..fb8eb5b5f 100644
--- a/packages/bruno-app/src/styles/globals.css
+++ b/packages/bruno-app/src/styles/globals.css
@@ -1,4 +1,3 @@
-
:root {
--color-brand: #546de5;
--color-text: rgb(52 52 52);
@@ -21,7 +20,8 @@
--color-method-head: rgb(52 52 52);
}
-html, body {
+html,
+body {
margin: 0;
padding: 0;
font-size: 1rem;
@@ -38,15 +38,18 @@ body {
font-size: 0.875rem;
}
-body::-webkit-scrollbar, .CodeMirror-vscrollbar::-webkit-scrollbar {
+body::-webkit-scrollbar,
+.CodeMirror-vscrollbar::-webkit-scrollbar {
width: 0.6rem;
}
-
-body::-webkit-scrollbar-track, .CodeMirror-vscrollbar::-webkit-scrollbar-track {
+
+body::-webkit-scrollbar-track,
+.CodeMirror-vscrollbar::-webkit-scrollbar-track {
background-color: #f1f1f1;
}
-
-body::-webkit-scrollbar-thumb, .CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
+
+body::-webkit-scrollbar-thumb,
+.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
background-color: #cdcdcd;
border-radius: 5rem;
}
diff --git a/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js b/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js
index 7a1a928b3..50f314dac 100644
--- a/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js
+++ b/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js
@@ -8,6 +8,7 @@
let CodeMirror;
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
+const { get } = require('lodash');
if (!SERVER_RENDERED) {
CodeMirror = require('codemirror');
@@ -20,7 +21,7 @@ if (!SERVER_RENDERED) {
// str is of format {{variableName}}, extract variableName
// we are seeing that from the gql query editor, the token string is of format variableName
const variableName = str.replace('{{', '').replace('}}', '').trim();
- const variableValue = options.variables[variableName];
+ const variableValue = get(options.variables, variableName);
const into = document.createElement('div');
const descriptionDiv = document.createElement('div');
diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js
index 3a0591324..80fe41dd3 100644
--- a/packages/bruno-app/src/utils/collections/index.js
+++ b/packages/bruno-app/src/utils/collections/index.js
@@ -542,6 +542,11 @@ export const getAllVariables = (collection) => {
return {
...environmentVariables,
- ...collection.collectionVariables
+ ...collection.collectionVariables,
+ process: {
+ env: {
+ ...collection.processEnvVariables
+ }
+ }
};
};
diff --git a/packages/bruno-app/src/utils/common/codemirror.js b/packages/bruno-app/src/utils/common/codemirror.js
index a565062e9..59daee837 100644
--- a/packages/bruno-app/src/utils/common/codemirror.js
+++ b/packages/bruno-app/src/utils/common/codemirror.js
@@ -1,3 +1,6 @@
+import get from 'lodash/get';
+import isString from 'lodash/isString';
+
let CodeMirror;
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
@@ -5,6 +8,11 @@ if (!SERVER_RENDERED) {
CodeMirror = require('codemirror');
}
+const pathFoundInVariables = (path, obj) => {
+ const value = get(obj, path);
+ return isString(value);
+};
+
export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
CodeMirror.defineMode('brunovariables', function (config, parserConfig) {
let variablesOverlay = {
@@ -15,7 +23,8 @@ export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
while ((ch = stream.next()) != null) {
if (ch == '}' && stream.next() == '}') {
stream.eat('}');
- if (word in variables) {
+ let found = pathFoundInVariables(word, variables);
+ if (found) {
return 'variable-valid';
} else {
return 'variable-invalid';
diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json
index d9f89baa3..5ec2fcfc4 100644
--- a/packages/bruno-electron/package.json
+++ b/packages/bruno-electron/package.json
@@ -27,6 +27,7 @@
"form-data": "^4.0.0",
"fs-extra": "^10.1.0",
"graphql": "^16.6.0",
+ "handlebars": "^4.7.8",
"is-valid-path": "^0.1.1",
"lodash": "^4.17.21",
"mustache": "^4.2.0",
diff --git a/packages/bruno-electron/src/app/watcher.js b/packages/bruno-electron/src/app/watcher.js
index 6edd0b617..5e6b27206 100644
--- a/packages/bruno-electron/src/app/watcher.js
+++ b/packages/bruno-electron/src/app/watcher.js
@@ -4,11 +4,13 @@ const path = require('path');
const chokidar = require('chokidar');
const { hasJsonExtension, hasBruExtension, writeFile } = require('../utils/filesystem');
const { bruToEnvJson, envJsonToBru, bruToJson, jsonToBru } = require('../bru');
+const { dotenvToJson } = require('@usebruno/lang');
const { isLegacyEnvFile, migrateLegacyEnvFile, isLegacyBruFile, migrateLegacyBruFile } = require('../bru/migrate');
const { itemSchema } = require('@usebruno/schema');
const { uuid } = require('../utils/common');
const { getRequestUid } = require('../cache/requestUids');
+const { setDotEnvVars } = require('../store/process-env');
const isJsonEnvironmentConfig = (pathname, collectionPath) => {
const dirname = path.dirname(pathname);
@@ -17,6 +19,13 @@ const isJsonEnvironmentConfig = (pathname, collectionPath) => {
return dirname === collectionPath && basename === 'environments.json';
};
+const isDotEnvFile = (pathname, collectionPath) => {
+ const dirname = path.dirname(pathname);
+ const basename = path.basename(pathname);
+
+ return dirname === collectionPath && basename === '.env';
+};
+
const isBruEnvironmentConfig = (pathname, collectionPath) => {
const dirname = path.dirname(pathname);
const envDirectory = path.join(collectionPath, 'environments');
@@ -125,6 +134,25 @@ const unlinkEnvironmentFile = async (win, pathname, collectionUid) => {
const add = async (win, pathname, collectionUid, collectionPath) => {
console.log(`watcher add: ${pathname}`);
+ if (isDotEnvFile(pathname, collectionPath)) {
+ try {
+ const content = fs.readFileSync(pathname, 'utf8');
+ const jsonData = dotenvToJson(content);
+
+ setDotEnvVars(collectionUid, jsonData);
+ const payload = {
+ collectionUid,
+ processEnvVariables: {
+ ...process.env,
+ ...jsonData
+ }
+ };
+ win.webContents.send('main:process-env-update', payload);
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
if (isJsonEnvironmentConfig(pathname, collectionPath)) {
try {
const dirname = path.dirname(pathname);
@@ -220,6 +248,25 @@ const addDirectory = (win, pathname, collectionUid, collectionPath) => {
};
const change = async (win, pathname, collectionUid, collectionPath) => {
+ if (isDotEnvFile(pathname, collectionPath)) {
+ try {
+ const content = fs.readFileSync(pathname, 'utf8');
+ const jsonData = dotenvToJson(content);
+
+ setDotEnvVars(collectionUid, jsonData);
+ const payload = {
+ collectionUid,
+ processEnvVariables: {
+ ...process.env,
+ ...jsonData
+ }
+ };
+ win.webContents.send('main:process-env-update', payload);
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
if (isBruEnvironmentConfig(pathname, collectionPath)) {
return changeEnvironmentFile(win, pathname, collectionUid);
}
diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js
index 7c5f95e19..bc8deb73e 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -13,6 +13,7 @@ const { uuid } = require('../../utils/common');
const interpolateVars = require('./interpolate-vars');
const { sortFolder, getAllRequestsInFolderRecursively } = require('./helper');
const { getPreferences } = require('../../store/preferences');
+const { getProcessEnvVars } = require('../../store/process-env');
// override the default escape function to prevent escaping
Mustache.escape = function (value) {
@@ -129,12 +130,14 @@ const registerNetworkIpc = (mainWindow) => {
collectionPath
);
- mainWindow.webContents.send('main:script-environment-update', {
- envVariables: result.envVariables,
- collectionVariables: result.collectionVariables,
- requestUid,
- collectionUid
- });
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ requestUid,
+ collectionUid
+ });
+ }
}
// run pre-request script
@@ -158,7 +161,9 @@ const registerNetworkIpc = (mainWindow) => {
});
}
- interpolateVars(request, envVars, collectionVariables);
+ const processEnvVars = getProcessEnvVars(collectionUid);
+
+ interpolateVars(request, envVars, collectionVariables, processEnvVars);
// stringify the request url encoded params
if (request.headers['content-type'] === 'application/x-www-form-urlencoded') {
@@ -222,12 +227,14 @@ const registerNetworkIpc = (mainWindow) => {
collectionPath
);
- mainWindow.webContents.send('main:script-environment-update', {
- envVariables: result.envVariables,
- collectionVariables: result.collectionVariables,
- requestUid,
- collectionUid
- });
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ requestUid,
+ collectionUid
+ });
+ }
}
// run post-response script
@@ -520,7 +527,21 @@ const registerNetworkIpc = (mainWindow) => {
const preRequestVars = get(request, 'vars.req', []);
if (preRequestVars && preRequestVars.length) {
const varsRuntime = new VarsRuntime();
- varsRuntime.runPreRequestVars(preRequestVars, request, envVars, collectionVariables, collectionPath);
+ const result = varsRuntime.runPreRequestVars(
+ preRequestVars,
+ request,
+ envVars,
+ collectionVariables,
+ collectionPath
+ );
+
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ collectionUid
+ });
+ }
}
// run pre-request script
@@ -543,8 +564,10 @@ const registerNetworkIpc = (mainWindow) => {
});
}
+ const processEnvVars = getProcessEnvVars(collectionUid);
+
// interpolate variables inside request
- interpolateVars(request, envVars, collectionVariables);
+ interpolateVars(request, envVars, collectionVariables, processEnvVars);
// todo:
// i have no clue why electron can't send the request object
@@ -587,11 +610,13 @@ const registerNetworkIpc = (mainWindow) => {
collectionPath
);
- mainWindow.webContents.send('main:script-environment-update', {
- envVariables: result.envVariables,
- collectionVariables: result.collectionVariables,
- collectionUid
- });
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ collectionUid
+ });
+ }
}
// run response script
diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
index 8c90e00a5..bfb0601da 100644
--- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js
+++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
@@ -1,24 +1,51 @@
-const Mustache = require('mustache');
-const { each, get, forOwn } = require('lodash');
+const Handlebars = require('handlebars');
+const { each, forOwn, cloneDeep } = require('lodash');
-// override the default escape function to prevent escaping
-Mustache.escape = function (value) {
- return value;
+const interpolateEnvVars = (str, processEnvVars) => {
+ if (!str || !str.length || typeof str !== 'string') {
+ return str;
+ }
+
+ const template = Handlebars.compile(str, { noEscape: true });
+
+ return template({
+ process: {
+ env: {
+ ...processEnvVars
+ }
+ }
+ });
};
-const interpolateVars = (request, envVars = {}, collectionVariables = {}) => {
+const interpolateVars = (request, envVars = {}, collectionVariables = {}, processEnvVars = {}) => {
+ // we clone envVars because we don't want to modify the original object
+ envVars = cloneDeep(envVars);
+
+ // envVars can inturn have values as {{process.env.VAR_NAME}}
+ // so we need to interpolate envVars first with processEnvVars
+ forOwn(envVars, (value, key) => {
+ envVars[key] = interpolateEnvVars(value, processEnvVars);
+ });
+
const interpolate = (str) => {
if (!str || !str.length || typeof str !== 'string') {
return str;
}
+ const template = Handlebars.compile(str, { noEscape: true });
+
// collectionVariables take precedence over envVars
const combinedVars = {
...envVars,
- ...collectionVariables
+ ...collectionVariables,
+ process: {
+ env: {
+ ...processEnvVars
+ }
+ }
};
- return Mustache.render(str, combinedVars);
+ return template(combinedVars);
};
request.url = interpolate(request.url);
diff --git a/packages/bruno-electron/src/store/process-env.js b/packages/bruno-electron/src/store/process-env.js
new file mode 100644
index 000000000..578d8df71
--- /dev/null
+++ b/packages/bruno-electron/src/store/process-env.js
@@ -0,0 +1,37 @@
+/**
+ * This file stores all the process.env variables under collection scope
+ *
+ * process.env variables are sourced from 2 places:
+ * 1. .env file in the root of the project
+ * 2. process.env variables set in the OS
+ *
+ * Multiple collections can be opened in the same electron app.
+ * Each collection's .env file can have different values for the same process.env variable.
+ */
+
+const dotEnvVars = {};
+
+// collectionUid is a hash based on the collection path)
+const getProcessEnvVars = (collectionUid) => {
+ // if there are no .env vars for this collection, return the process.env
+ if (!dotEnvVars[collectionUid]) {
+ return {
+ ...process.env
+ };
+ }
+
+ // if there are .env vars for this collection, return the process.env merged with the .env vars
+ return {
+ ...process.env,
+ ...dotEnvVars[collectionUid]
+ };
+};
+
+const setDotEnvVars = (collectionUid, envVars) => {
+ dotEnvVars[collectionUid] = envVars;
+};
+
+module.exports = {
+ getProcessEnvVars,
+ setDotEnvVars
+};
diff --git a/packages/bruno-electron/src/utils/common.js b/packages/bruno-electron/src/utils/common.js
index d85d137dd..83d22c7ce 100644
--- a/packages/bruno-electron/src/utils/common.js
+++ b/packages/bruno-electron/src/utils/common.js
@@ -41,10 +41,39 @@ const generateUidBasedOnHash = (str) => {
return `${hash}`.padEnd(21, '0');
};
+const flattenDataForDotNotation = (data) => {
+ var result = {};
+ function recurse(current, prop) {
+ if (Object(current) !== current) {
+ result[prop] = current;
+ } else if (Array.isArray(current)) {
+ for (var i = 0, l = current.length; i < l; i++) {
+ recurse(current[i], prop + '[' + i + ']');
+ }
+ if (l == 0) {
+ result[prop] = [];
+ }
+ } else {
+ var isEmpty = true;
+ for (var p in current) {
+ isEmpty = false;
+ recurse(current[p], prop ? prop + '.' + p : p);
+ }
+ if (isEmpty && prop) {
+ result[prop] = {};
+ }
+ }
+ }
+
+ recurse(data, '');
+ return result;
+};
+
module.exports = {
uuid,
stringifyJson,
parseJson,
simpleHash,
- generateUidBasedOnHash
+ generateUidBasedOnHash,
+ flattenDataForDotNotation
};
diff --git a/packages/bruno-electron/tests/utils/common.spec.js b/packages/bruno-electron/tests/utils/common.spec.js
new file mode 100644
index 000000000..077aac16d
--- /dev/null
+++ b/packages/bruno-electron/tests/utils/common.spec.js
@@ -0,0 +1,85 @@
+const { flattenDataForDotNotation } = require('../../src/utils/common');
+
+describe('utils: flattenDataForDotNotation', () => {
+ test('Flatten a simple object with dot notation', () => {
+ const input = {
+ person: {
+ name: 'John',
+ age: 30,
+ },
+ };
+
+ const expectedOutput = {
+ 'person.name': 'John',
+ 'person.age': 30,
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an object with nested arrays', () => {
+ const input = {
+ users: [
+ { name: 'Alice', age: 25 },
+ { name: 'Bob', age: 28 },
+ ],
+ };
+
+ const expectedOutput = {
+ 'users[0].name': 'Alice',
+ 'users[0].age': 25,
+ 'users[1].name': 'Bob',
+ 'users[1].age': 28,
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an empty object', () => {
+ const input = {};
+
+ const expectedOutput = {};
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an object with nested objects', () => {
+ const input = {
+ person: {
+ name: 'Alice',
+ address: {
+ city: 'New York',
+ zipcode: '10001',
+ },
+ },
+ };
+
+ const expectedOutput = {
+ 'person.name': 'Alice',
+ 'person.address.city': 'New York',
+ 'person.address.zipcode': '10001',
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an object with arrays of objects', () => {
+ const input = {
+ teams: [
+ { name: 'Team A', members: ['Alice', 'Bob'] },
+ { name: 'Team B', members: ['Charlie', 'David'] },
+ ],
+ };
+
+ const expectedOutput = {
+ 'teams[0].name': 'Team A',
+ 'teams[0].members[0]': 'Alice',
+ 'teams[0].members[1]': 'Bob',
+ 'teams[1].name': 'Team B',
+ 'teams[1].members[0]': 'Charlie',
+ 'teams[1].members[1]': 'David',
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+});
\ No newline at end of file
diff --git a/packages/bruno-lang/src/index.js b/packages/bruno-lang/src/index.js
index bb7f35a80..f27179c45 100644
--- a/packages/bruno-lang/src/index.js
+++ b/packages/bruno-lang/src/index.js
@@ -4,6 +4,7 @@ const bruToJsonV2 = require('../v2/src/bruToJson');
const jsonToBruV2 = require('../v2/src/jsonToBru');
const bruToEnvJsonV2 = require('../v2/src/envToJson');
const envJsonToBruV2 = require('../v2/src/jsonToEnv');
+const dotenvToJson = require('../v2/src/dotenvToJson');
module.exports = {
bruToJson,
@@ -14,5 +15,7 @@ module.exports = {
bruToJsonV2,
jsonToBruV2,
bruToEnvJsonV2,
- envJsonToBruV2
+ envJsonToBruV2,
+
+ dotenvToJson
};
|