mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-07 08:34:15 +01:00
feat(#1460): use new interpolation lib in app, electron, cli
This commit is contained in:
parent
c5986896d1
commit
7ba9b839da
77
package-lock.json
generated
77
package-lock.json
generated
@ -15,7 +15,6 @@
|
||||
"packages/bruno-js",
|
||||
"packages/bruno-lang",
|
||||
"packages/bruno-tests",
|
||||
"packages/bruno-testbench",
|
||||
"packages/bruno-toml",
|
||||
"packages/bruno-graphql-docs"
|
||||
],
|
||||
@ -5418,10 +5417,6 @@
|
||||
"resolved": "packages/bruno-schema",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@usebruno/testbench": {
|
||||
"resolved": "packages/bruno-testbench",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@usebruno/tests": {
|
||||
"resolved": "packages/bruno-tests",
|
||||
"link": true
|
||||
@ -7392,16 +7387,6 @@
|
||||
"version": "4.0.0",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/config": {
|
||||
"version": "3.3.9",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json5": "^2.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/config-chain": {
|
||||
"version": "1.1.13",
|
||||
"dev": true,
|
||||
@ -11914,6 +11899,7 @@
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.3",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
@ -17928,6 +17914,7 @@
|
||||
"@reduxjs/toolkit": "^1.8.0",
|
||||
"@tabler/icons": "^1.46.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/graphql-docs": "0.1.0",
|
||||
"@usebruno/schema": "0.6.0",
|
||||
"axios": "^1.5.1",
|
||||
@ -17944,7 +17931,6 @@
|
||||
"graphiql": "^1.5.9",
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-request": "^3.7.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"httpsnippet": "^3.0.1",
|
||||
"idb": "^7.0.0",
|
||||
"immer": "^9.0.15",
|
||||
@ -18145,6 +18131,7 @@
|
||||
"version": "1.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/js": "0.9.4",
|
||||
"@usebruno/lang": "0.9.0",
|
||||
"axios": "^1.5.1",
|
||||
@ -18153,7 +18140,6 @@
|
||||
"decomment": "^0.9.5",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"inquirer": "^9.1.4",
|
||||
@ -18253,6 +18239,7 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/credential-providers": "^3.425.0",
|
||||
"@n8n/vm2": "^3.9.23",
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/js": "0.9.4",
|
||||
"@usebruno/lang": "0.9.0",
|
||||
"@usebruno/schema": "0.6.0",
|
||||
@ -18271,7 +18258,6 @@
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"graphql": "^16.6.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"is-valid-path": "^0.1.1",
|
||||
@ -18603,6 +18589,7 @@
|
||||
"packages/bruno-testbench": {
|
||||
"name": "@usebruno/testbench",
|
||||
"version": "1.0.0",
|
||||
"extraneous": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.0",
|
||||
@ -18615,21 +18602,8 @@
|
||||
"multer": "^1.4.5-lts.1"
|
||||
}
|
||||
},
|
||||
"packages/bruno-testbench/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"packages/bruno-testbench/node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"packages/bruno-tests": {
|
||||
"name": "@usebruno/tests",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -22559,6 +22533,7 @@
|
||||
"@reduxjs/toolkit": "^1.8.0",
|
||||
"@tabler/icons": "^1.46.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/graphql-docs": "0.1.0",
|
||||
"@usebruno/schema": "0.6.0",
|
||||
"axios": "^1.5.1",
|
||||
@ -22579,7 +22554,6 @@
|
||||
"graphiql": "^1.5.9",
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-request": "^3.7.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"html-loader": "^3.0.1",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"httpsnippet": "^3.0.1",
|
||||
@ -22709,6 +22683,7 @@
|
||||
"@usebruno/cli": {
|
||||
"version": "file:packages/bruno-cli",
|
||||
"requires": {
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/js": "0.9.4",
|
||||
"@usebruno/lang": "0.9.0",
|
||||
"axios": "^1.5.1",
|
||||
@ -22717,7 +22692,6 @@
|
||||
"decomment": "^0.9.5",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"inquirer": "^9.1.4",
|
||||
@ -22885,30 +22859,6 @@
|
||||
"version": "file:packages/bruno-schema",
|
||||
"requires": {}
|
||||
},
|
||||
"@usebruno/testbench": {
|
||||
"version": "file:packages/bruno-testbench",
|
||||
"requires": {
|
||||
"body-parser": "^1.20.0",
|
||||
"config": "^3.3.8",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.1",
|
||||
"express-xml-bodyparser": "^0.3.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"multer": "^1.4.5-lts.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": {
|
||||
"version": "2.0.1"
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@usebruno/tests": {
|
||||
"version": "file:packages/bruno-tests",
|
||||
"requires": {
|
||||
@ -23753,6 +23703,7 @@
|
||||
"requires": {
|
||||
"@aws-sdk/credential-providers": "^3.425.0",
|
||||
"@n8n/vm2": "^3.9.23",
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/js": "0.9.4",
|
||||
"@usebruno/lang": "0.9.0",
|
||||
"@usebruno/schema": "0.6.0",
|
||||
@ -23775,7 +23726,6 @@
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"graphql": "^16.6.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"is-valid-path": "^0.1.1",
|
||||
@ -24373,12 +24323,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"version": "3.3.9",
|
||||
"requires": {
|
||||
"json5": "^2.2.3"
|
||||
}
|
||||
},
|
||||
"config-chain": {
|
||||
"version": "1.1.13",
|
||||
"dev": true,
|
||||
@ -27310,7 +27254,8 @@
|
||||
"version": "5.0.1"
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.3"
|
||||
"version": "2.2.3",
|
||||
"dev": true
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "6.1.0",
|
||||
|
@ -18,6 +18,7 @@
|
||||
"@reduxjs/toolkit": "^1.8.0",
|
||||
"@tabler/icons": "^1.46.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/graphql-docs": "0.1.0",
|
||||
"@usebruno/schema": "0.6.0",
|
||||
"axios": "^1.5.1",
|
||||
@ -34,7 +35,6 @@
|
||||
"graphiql": "^1.5.9",
|
||||
"graphql": "^16.6.0",
|
||||
"graphql-request": "^3.7.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"httpsnippet": "^3.0.1",
|
||||
"idb": "^7.0.0",
|
||||
"immer": "^9.0.15",
|
||||
|
@ -4,17 +4,19 @@ import CodeView from './CodeView';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { isValidUrl } from 'utils/url/index';
|
||||
import get from 'lodash/get';
|
||||
import handlebars from 'handlebars';
|
||||
import { findEnvironmentInCollection } from 'utils/collections';
|
||||
|
||||
// Todo: Fix this
|
||||
// import { interpolate } from '@usebruno/common';
|
||||
const brunoCommon = require('@usebruno/common');
|
||||
const { interpolate } = brunoCommon.default;
|
||||
|
||||
const interpolateUrl = ({ url, envVars, collectionVariables, processEnvVars }) => {
|
||||
if (!url || !url.length || typeof url !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const template = handlebars.compile(url, { noEscape: true });
|
||||
|
||||
return template({
|
||||
return interpolate(url, {
|
||||
...envVars,
|
||||
...collectionVariables,
|
||||
process: {
|
||||
|
@ -24,6 +24,7 @@
|
||||
"package.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/js": "0.9.4",
|
||||
"@usebruno/lang": "0.9.0",
|
||||
"axios": "^1.5.1",
|
||||
@ -32,7 +33,6 @@
|
||||
"decomment": "^0.9.5",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"inquirer": "^9.1.4",
|
||||
|
@ -1,21 +1,5 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const { forOwn, cloneDeep } = require('lodash');
|
||||
|
||||
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 { interpolate } = require('@usebruno/common');
|
||||
|
||||
const interpolateString = (str, { envVars, collectionVariables, processEnvVars }) => {
|
||||
if (!str || !str.length || typeof str !== 'string') {
|
||||
@ -31,10 +15,14 @@ const interpolateString = (str, { envVars, collectionVariables, processEnvVars }
|
||||
// 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);
|
||||
envVars[key] = interpolate(value, {
|
||||
process: {
|
||||
env: {
|
||||
...processEnvVars
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const template = Handlebars.compile(str, { noEscape: true });
|
||||
|
||||
// collectionVariables take precedence over envVars
|
||||
const combinedVars = {
|
||||
@ -47,7 +35,7 @@ const interpolateString = (str, { envVars, collectionVariables, processEnvVars }
|
||||
}
|
||||
};
|
||||
|
||||
return template(combinedVars);
|
||||
return interpolate(str, combinedVars);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
@ -1,4 +1,4 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const { interpolate } = require('@usebruno/common');
|
||||
const { each, forOwn, cloneDeep } = require('lodash');
|
||||
|
||||
const getContentType = (headers = {}) => {
|
||||
@ -12,24 +12,6 @@ const getContentType = (headers = {}) => {
|
||||
return contentType;
|
||||
};
|
||||
|
||||
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 varsRegex = /(?<!\\)\{\{(?!process\.env\.\w+)(.*\..*)\}\}/g;
|
||||
|
||||
const interpolateVars = (request, envVars = {}, collectionVariables = {}, processEnvVars = {}) => {
|
||||
// we clone envVars because we don't want to modify the original object
|
||||
envVars = cloneDeep(envVars);
|
||||
@ -37,20 +19,20 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
// 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);
|
||||
envVars[key] = interpolate(value, {
|
||||
process: {
|
||||
env: {
|
||||
...processEnvVars
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const interpolate = (str) => {
|
||||
const _interpolate = (str) => {
|
||||
if (!str || !str.length || typeof str !== 'string') {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (varsRegex.test(str)) {
|
||||
// Handlebars doesn't allow dots as identifiers, so we need to use literal segments
|
||||
str = str.replaceAll(varsRegex, '{{[$1]}}');
|
||||
}
|
||||
const template = Handlebars.compile(str, { noEscape: true });
|
||||
|
||||
// collectionVariables take precedence over envVars
|
||||
const combinedVars = {
|
||||
...envVars,
|
||||
@ -62,14 +44,14 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
}
|
||||
};
|
||||
|
||||
return template(combinedVars);
|
||||
return interpolate(str, combinedVars);
|
||||
};
|
||||
|
||||
request.url = interpolate(request.url);
|
||||
request.url = _interpolate(request.url);
|
||||
|
||||
forOwn(request.headers, (value, key) => {
|
||||
delete request.headers[key];
|
||||
request.headers[interpolate(key)] = interpolate(value);
|
||||
request.headers[_interpolate(key)] = _interpolate(value);
|
||||
});
|
||||
|
||||
const contentType = getContentType(request.headers);
|
||||
@ -78,40 +60,40 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
if (typeof request.data === 'object') {
|
||||
try {
|
||||
let parsed = JSON.stringify(request.data);
|
||||
parsed = interpolate(parsed);
|
||||
parsed = _interpolate(parsed);
|
||||
request.data = JSON.parse(parsed);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
if (typeof request.data === 'string') {
|
||||
if (request.data.length) {
|
||||
request.data = interpolate(request.data);
|
||||
request.data = _interpolate(request.data);
|
||||
}
|
||||
}
|
||||
} else if (contentType === 'application/x-www-form-urlencoded') {
|
||||
if (typeof request.data === 'object') {
|
||||
try {
|
||||
let parsed = JSON.stringify(request.data);
|
||||
parsed = interpolate(parsed);
|
||||
parsed = _interpolate(parsed);
|
||||
request.data = JSON.parse(parsed);
|
||||
} catch (err) {}
|
||||
}
|
||||
} else {
|
||||
request.data = interpolate(request.data);
|
||||
request.data = _interpolate(request.data);
|
||||
}
|
||||
|
||||
each(request.params, (param) => {
|
||||
param.value = interpolate(param.value);
|
||||
param.value = _interpolate(param.value);
|
||||
});
|
||||
|
||||
if (request.proxy) {
|
||||
request.proxy.protocol = interpolate(request.proxy.protocol);
|
||||
request.proxy.hostname = interpolate(request.proxy.hostname);
|
||||
request.proxy.port = interpolate(request.proxy.port);
|
||||
request.proxy.protocol = _interpolate(request.proxy.protocol);
|
||||
request.proxy.hostname = _interpolate(request.proxy.hostname);
|
||||
request.proxy.port = _interpolate(request.proxy.port);
|
||||
|
||||
if (request.proxy.auth) {
|
||||
request.proxy.auth.username = interpolate(request.proxy.auth.username);
|
||||
request.proxy.auth.password = interpolate(request.proxy.auth.password);
|
||||
request.proxy.auth.username = _interpolate(request.proxy.auth.username);
|
||||
request.proxy.auth.password = _interpolate(request.proxy.auth.password);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,8 +101,8 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
// need to refactor this in the future
|
||||
// the request.auth (basic auth) object gets set inside the prepare-request.js file
|
||||
if (request.auth) {
|
||||
const username = interpolate(request.auth.username) || '';
|
||||
const password = interpolate(request.auth.password) || '';
|
||||
const username = _interpolate(request.auth.username) || '';
|
||||
const password = _interpolate(request.auth.password) || '';
|
||||
|
||||
// use auth header based approach and delete the request.auth object
|
||||
request.headers['authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
||||
|
@ -82,3 +82,90 @@ describe('interpolate', () => {
|
||||
expect(result).toBe('Hello, my name is Not Bruno and I am 4 years old');
|
||||
});
|
||||
});
|
||||
|
||||
describe('interpolate - template edge cases', () => {
|
||||
it('should return the input string if the template is not a string', () => {
|
||||
const inputString = 123;
|
||||
const inputObject = {
|
||||
user: 'Bruno'
|
||||
};
|
||||
|
||||
const result = interpolate(inputString as any, inputObject);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
|
||||
it('should return the input string if the template is null', () => {
|
||||
const inputString = null;
|
||||
const inputObject = {
|
||||
user: 'Bruno'
|
||||
};
|
||||
|
||||
const result = interpolate(inputString as any, inputObject);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
|
||||
it('should return the input string if the template is undefined', () => {
|
||||
const inputString = undefined;
|
||||
const inputObject = {
|
||||
user: 'Bruno'
|
||||
};
|
||||
|
||||
const result = interpolate(inputString as any, inputObject);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
|
||||
it('should return the input string if the template is empty', () => {
|
||||
const inputString = '';
|
||||
const inputObject = {
|
||||
user: 'Bruno'
|
||||
};
|
||||
|
||||
const result = interpolate(inputString, inputObject);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
|
||||
it('should return preserve whitespaces', () => {
|
||||
const inputString = ' ';
|
||||
const inputObject = {
|
||||
user: 'Bruno'
|
||||
};
|
||||
|
||||
const result = interpolate(inputString, inputObject);
|
||||
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
});
|
||||
|
||||
describe('interpolate - value edge cases', () => {
|
||||
it('should return the input string if the value is not an object', () => {
|
||||
const inputString = 'Hello, my name is {{user.name}}';
|
||||
const inputObject = 123;
|
||||
|
||||
const result = interpolate(inputString, inputObject as any);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
|
||||
it('should return the input string if the value is null', () => {
|
||||
const inputString = 'Hello, my name is {{user.name}}';
|
||||
const inputObject = null;
|
||||
|
||||
const result = interpolate(inputString, inputObject as any);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
|
||||
it('should return the input string if the value is undefined', () => {
|
||||
const inputString = 'Hello, my name is {{user.name}}';
|
||||
const inputObject = undefined;
|
||||
|
||||
const result = interpolate(inputString, inputObject as any);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
|
||||
it('should return the input string if the value is empty', () => {
|
||||
const inputString = 'Hello, my name is {{user.name}}';
|
||||
const inputObject = {};
|
||||
|
||||
const result = interpolate(inputString, inputObject);
|
||||
expect(result).toBe(inputString);
|
||||
});
|
||||
});
|
||||
|
@ -20,6 +20,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/credential-providers": "^3.425.0",
|
||||
"@usebruno/common": "0.1.0",
|
||||
"@usebruno/js": "0.9.4",
|
||||
"@usebruno/lang": "0.9.0",
|
||||
"@usebruno/schema": "0.6.0",
|
||||
@ -38,7 +39,6 @@
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"graphql": "^16.6.0",
|
||||
"handlebars": "^4.7.8",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.2",
|
||||
"is-valid-path": "^0.1.1",
|
||||
|
@ -1,21 +1,5 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const { forOwn, cloneDeep } = require('lodash');
|
||||
|
||||
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 { interpolate } = require('@usebruno/common');
|
||||
|
||||
const interpolateString = (str, { envVars, collectionVariables, processEnvVars }) => {
|
||||
if (!str || !str.length || typeof str !== 'string') {
|
||||
@ -31,10 +15,14 @@ const interpolateString = (str, { envVars, collectionVariables, processEnvVars }
|
||||
// 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);
|
||||
envVars[key] = interpolate(value, {
|
||||
process: {
|
||||
env: {
|
||||
...processEnvVars
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const template = Handlebars.compile(str, { noEscape: true });
|
||||
|
||||
// collectionVariables take precedence over envVars
|
||||
const combinedVars = {
|
||||
@ -47,7 +35,7 @@ const interpolateString = (str, { envVars, collectionVariables, processEnvVars }
|
||||
}
|
||||
};
|
||||
|
||||
return template(combinedVars);
|
||||
return interpolate(str, combinedVars);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
@ -1,4 +1,4 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const { interpolate } = require('@usebruno/common');
|
||||
const { each, forOwn, cloneDeep } = require('lodash');
|
||||
|
||||
const getContentType = (headers = {}) => {
|
||||
@ -12,24 +12,6 @@ const getContentType = (headers = {}) => {
|
||||
return contentType;
|
||||
};
|
||||
|
||||
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 varsRegex = /(?<!\\)\{\{(?!process\.env\.\w+)(.*\..*)\}\}/g;
|
||||
|
||||
const interpolateVars = (request, envVars = {}, collectionVariables = {}, processEnvVars = {}) => {
|
||||
// we clone envVars because we don't want to modify the original object
|
||||
envVars = cloneDeep(envVars);
|
||||
@ -37,20 +19,20 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
// 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);
|
||||
envVars[key] = interpolate(value, {
|
||||
process: {
|
||||
env: {
|
||||
...processEnvVars
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const interpolate = (str) => {
|
||||
const _interpolate = (str) => {
|
||||
if (!str || !str.length || typeof str !== 'string') {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (varsRegex.test(str)) {
|
||||
// Handlebars doesn't allow dots as identifiers, so we need to use literal segments
|
||||
str = str.replaceAll(varsRegex, '{{[$1]}}');
|
||||
}
|
||||
const template = Handlebars.compile(str, { noEscape: true });
|
||||
|
||||
// collectionVariables take precedence over envVars
|
||||
const combinedVars = {
|
||||
...envVars,
|
||||
@ -62,14 +44,14 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
}
|
||||
};
|
||||
|
||||
return template(combinedVars);
|
||||
return interpolate(str, combinedVars);
|
||||
};
|
||||
|
||||
request.url = interpolate(request.url);
|
||||
request.url = _interpolate(request.url);
|
||||
|
||||
forOwn(request.headers, (value, key) => {
|
||||
delete request.headers[key];
|
||||
request.headers[interpolate(key)] = interpolate(value);
|
||||
request.headers[_interpolate(key)] = _interpolate(value);
|
||||
});
|
||||
|
||||
const contentType = getContentType(request.headers);
|
||||
@ -78,40 +60,40 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
if (typeof request.data === 'object') {
|
||||
try {
|
||||
let parsed = JSON.stringify(request.data);
|
||||
parsed = interpolate(parsed);
|
||||
parsed = _interpolate(parsed);
|
||||
request.data = JSON.parse(parsed);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
if (typeof request.data === 'string') {
|
||||
if (request.data.length) {
|
||||
request.data = interpolate(request.data);
|
||||
request.data = _interpolate(request.data);
|
||||
}
|
||||
}
|
||||
} else if (contentType === 'application/x-www-form-urlencoded') {
|
||||
if (typeof request.data === 'object') {
|
||||
try {
|
||||
let parsed = JSON.stringify(request.data);
|
||||
parsed = interpolate(parsed);
|
||||
parsed = _interpolate(parsed);
|
||||
request.data = JSON.parse(parsed);
|
||||
} catch (err) {}
|
||||
}
|
||||
} else {
|
||||
request.data = interpolate(request.data);
|
||||
request.data = _interpolate(request.data);
|
||||
}
|
||||
|
||||
each(request.params, (param) => {
|
||||
param.value = interpolate(param.value);
|
||||
param.value = _interpolate(param.value);
|
||||
});
|
||||
|
||||
if (request.proxy) {
|
||||
request.proxy.protocol = interpolate(request.proxy.protocol);
|
||||
request.proxy.hostname = interpolate(request.proxy.hostname);
|
||||
request.proxy.port = interpolate(request.proxy.port);
|
||||
request.proxy.protocol = _interpolate(request.proxy.protocol);
|
||||
request.proxy.hostname = _interpolate(request.proxy.hostname);
|
||||
request.proxy.port = _interpolate(request.proxy.port);
|
||||
|
||||
if (request.proxy.auth) {
|
||||
request.proxy.auth.username = interpolate(request.proxy.auth.username);
|
||||
request.proxy.auth.password = interpolate(request.proxy.auth.password);
|
||||
request.proxy.auth.username = _interpolate(request.proxy.auth.username);
|
||||
request.proxy.auth.password = _interpolate(request.proxy.auth.password);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,8 +101,8 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
// need to refactor this in the future
|
||||
// the request.auth (basic auth) object gets set inside the prepare-request.js file
|
||||
if (request.auth) {
|
||||
const username = interpolate(request.auth.username) || '';
|
||||
const password = interpolate(request.auth.password) || '';
|
||||
const username = _interpolate(request.auth.username) || '';
|
||||
const password = _interpolate(request.auth.password) || '';
|
||||
|
||||
// use auth header based approach and delete the request.auth object
|
||||
request.headers['authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
||||
@ -129,18 +111,18 @@ const interpolateVars = (request, envVars = {}, collectionVariables = {}, proces
|
||||
|
||||
// interpolate vars for aws sigv4 auth
|
||||
if (request.awsv4config) {
|
||||
request.awsv4config.accessKeyId = interpolate(request.awsv4config.accessKeyId) || '';
|
||||
request.awsv4config.secretAccessKey = interpolate(request.awsv4config.secretAccessKey) || '';
|
||||
request.awsv4config.sessionToken = interpolate(request.awsv4config.sessionToken) || '';
|
||||
request.awsv4config.service = interpolate(request.awsv4config.service) || '';
|
||||
request.awsv4config.region = interpolate(request.awsv4config.region) || '';
|
||||
request.awsv4config.profileName = interpolate(request.awsv4config.profileName) || '';
|
||||
request.awsv4config.accessKeyId = _interpolate(request.awsv4config.accessKeyId) || '';
|
||||
request.awsv4config.secretAccessKey = _interpolate(request.awsv4config.secretAccessKey) || '';
|
||||
request.awsv4config.sessionToken = _interpolate(request.awsv4config.sessionToken) || '';
|
||||
request.awsv4config.service = _interpolate(request.awsv4config.service) || '';
|
||||
request.awsv4config.region = _interpolate(request.awsv4config.region) || '';
|
||||
request.awsv4config.profileName = _interpolate(request.awsv4config.profileName) || '';
|
||||
}
|
||||
|
||||
// interpolate vars for digest auth
|
||||
if (request.digestConfig) {
|
||||
request.digestConfig.username = interpolate(request.digestConfig.username) || '';
|
||||
request.digestConfig.password = interpolate(request.digestConfig.password) || '';
|
||||
request.digestConfig.username = _interpolate(request.digestConfig.username) || '';
|
||||
request.digestConfig.password = _interpolate(request.digestConfig.password) || '';
|
||||
}
|
||||
|
||||
return request;
|
||||
|
@ -1,10 +1,10 @@
|
||||
const Handlebars = require('handlebars');
|
||||
const { interpolate } = require('@usebruno/common');
|
||||
const { getIntrospectionQuery } = require('graphql');
|
||||
const { setAuthHeaders } = require('./prepare-request');
|
||||
|
||||
const prepareGqlIntrospectionRequest = (endpoint, envVars, request, collectionRoot) => {
|
||||
if (endpoint && endpoint.length) {
|
||||
endpoint = Handlebars.compile(endpoint, { noEscape: true })(envVars);
|
||||
endpoint = interpolate(endpoint, envVars);
|
||||
}
|
||||
|
||||
const queryParams = {
|
||||
|
@ -70,13 +70,6 @@ describe('interpolate-vars: interpolateVars', () => {
|
||||
|
||||
describe('Does NOT interpolate string', () => {
|
||||
describe('With environment variables', () => {
|
||||
it('If the var is escaped', async () => {
|
||||
const request = { method: 'GET', url: `\\{{test.url}}` };
|
||||
|
||||
const result = interpolateVars(request, { 'test.url': 'test.com' }, null, null);
|
||||
expect(result.url).toEqual('{{test.url}}');
|
||||
});
|
||||
|
||||
it("If it's not a var (no braces)", async () => {
|
||||
const request = { method: 'GET', url: 'test' };
|
||||
|
||||
@ -106,25 +99,5 @@ describe('interpolate-vars: interpolateVars', () => {
|
||||
expect(result.data).toEqual(gqlBody);
|
||||
});
|
||||
});
|
||||
|
||||
describe('With process environment variables', () => {
|
||||
it("If there's a var that doesn't start with 'process.env.'", async () => {
|
||||
const request = { method: 'GET', url: '{{process-env-TEST_VAR}}' };
|
||||
|
||||
const result = interpolateVars(request, null, null, { TEST_VAR: 'test.com' });
|
||||
expect(result.url).toEqual('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Throws an error', () => {
|
||||
it("If there's a var with an invalid character in its name", async () => {
|
||||
'!@#%^&*()[{]}=+,<>;\\|'.split('').forEach((character) => {
|
||||
const request = { method: 'GET', url: `{{test${character}Url}}` };
|
||||
expect(() => interpolateVars(request, { [`test${character}Url`]: 'test.com' }, null, null)).toThrow(
|
||||
/Parse error.*/
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
1
packages/bruno-tests/collection/.env
Normal file
1
packages/bruno-tests/collection/.env
Normal file
@ -0,0 +1 @@
|
||||
PROC_ENV_VAR=woof
|
1
packages/bruno-tests/collection/.gitignore
vendored
Normal file
1
packages/bruno-tests/collection/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
!.env
|
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: echo plaintext
|
||||
type: http
|
||||
seq: 3
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
|
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: echo xml parsed
|
||||
type: http
|
||||
seq: 4
|
||||
seq: 3
|
||||
}
|
||||
|
||||
post {
|
||||
|
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: echo xml raw
|
||||
type: http
|
||||
seq: 5
|
||||
seq: 4
|
||||
}
|
||||
|
||||
post {
|
||||
|
@ -2,4 +2,7 @@ vars {
|
||||
host: http://localhost:80
|
||||
bearer_auth_token: your_secret_token
|
||||
basic_auth_password: della
|
||||
env.var1: envVar1
|
||||
env-var2: envVar2
|
||||
bark: {{process.env.PROC_ENV_VAR}}
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
meta {
|
||||
name: env vars
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{host}}/api/echo/json
|
||||
body: json
|
||||
auth: none
|
||||
}
|
||||
|
||||
auth:basic {
|
||||
username: asd
|
||||
password: j
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token:
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"envVar1": "{{env.var1}}",
|
||||
"envVar2": "{{env-var2}}"
|
||||
}
|
||||
}
|
||||
|
||||
assert {
|
||||
res.status: eq 200
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should return json", function() {
|
||||
expect(res.getBody()).to.eql({
|
||||
"envVar1": "envVar1",
|
||||
"envVar2": "envVar2"
|
||||
});
|
||||
});
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
meta {
|
||||
name: missing values
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{host}}/api/echo/json?foo={{undefinedVar}}
|
||||
body: json
|
||||
auth: none
|
||||
}
|
||||
|
||||
query {
|
||||
foo: {{undefinedVar}}
|
||||
}
|
||||
|
||||
auth:basic {
|
||||
username: asd
|
||||
password: j
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token:
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"hello": "{{undefinedVar2}}"
|
||||
}
|
||||
}
|
||||
|
||||
assert {
|
||||
res.status: eq 200
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should return json", function() {
|
||||
const url = req.getUrl();
|
||||
expect(url).to.equal("http://localhost:80/api/echo/json?foo={{undefinedVar}}");
|
||||
|
||||
const data = res.getBody();
|
||||
expect(res.getBody()).to.eql({
|
||||
"hello": "{{undefinedVar2}}"
|
||||
});
|
||||
});
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
meta {
|
||||
name: process env vars
|
||||
type: http
|
||||
seq: 4
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{host}}/api/echo/json
|
||||
body: json
|
||||
auth: none
|
||||
}
|
||||
|
||||
auth:basic {
|
||||
username: asd
|
||||
password: j
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token:
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"bark": "{{bark}}",
|
||||
"bark2": "{{process.env.PROC_ENV_VAR}}"
|
||||
}
|
||||
}
|
||||
|
||||
assert {
|
||||
res.status: eq 200
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should return json", function() {
|
||||
expect(res.getBody()).to.eql({
|
||||
"bark": "woof",
|
||||
"bark2": "woof"
|
||||
});
|
||||
});
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
meta {
|
||||
name: runtime vars
|
||||
type: http
|
||||
seq: 3
|
||||
}
|
||||
|
||||
post {
|
||||
url: {{host}}/api/echo/text
|
||||
body: text
|
||||
auth: none
|
||||
}
|
||||
|
||||
auth:basic {
|
||||
username: asd
|
||||
password: j
|
||||
}
|
||||
|
||||
auth:bearer {
|
||||
token:
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"envVar1": "{{env.var1}}",
|
||||
"envVar2": "{{env-var2}}"
|
||||
}
|
||||
}
|
||||
|
||||
body:text {
|
||||
Hi, I am {{rUser.full_name}},
|
||||
I am {{rUser.age}} years old.
|
||||
My favorite food is {{rUser.fav-food[0]}} and {{rUser.fav-food[1]}}.
|
||||
I like attention: {{rUser.want.attention}}
|
||||
}
|
||||
|
||||
assert {
|
||||
res.status: eq 200
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
bru.setVar("rUser", {
|
||||
full_name: 'Bruno',
|
||||
age: 4,
|
||||
'fav-food': ['egg', 'meat'],
|
||||
'want.attention': true
|
||||
});
|
||||
}
|
||||
|
||||
tests {
|
||||
test("should return json", function() {
|
||||
const expectedResponse = `Hi, I am Bruno,
|
||||
I am 4 years old.
|
||||
My favorite food is egg and meat.
|
||||
I like attention: true`;
|
||||
expect(res.getBody()).to.equal(expectedResponse);
|
||||
});
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user