diff --git a/docs/contributing/contributing_fr.md b/docs/contributing/contributing_fr.md index bc41465ee6..78cdef3455 100644 --- a/docs/contributing/contributing_fr.md +++ b/docs/contributing/contributing_fr.md @@ -27,7 +27,6 @@ Vous aurez besoin de [Node v18.x ou la dernière version LTS](https://nodejs.org Bruno est développé comme une application _client lourd_. Vous devrez charger l'application en démarrant nextjs dans un premier terminal, puis démarre l'application Electron dans un second. - ### Dépendances - NodeJS v18 @@ -68,7 +67,6 @@ done find . -type f -name "package-lock.json" -delete ``` - ### Tests ```bash @@ -79,7 +77,6 @@ npm test --workspace=packages/bruno-schema npm test --workspace=packages/bruno-lang ``` - ### Ouvrir une Pull Request - Merci de conserver les PR minimes et focalisées sur un seul objectif @@ -87,4 +84,4 @@ npm test --workspace=packages/bruno-lang - feature/[feature name]: Cette branche doit contenir une fonctionnalité spécifique - Exemple : feature/dark-mode - bugfix/[bug name]: Cette branche doit contenir seulement une solution pour un bug spécifique - - Exemple : bugfix/bug-1 \ No newline at end of file + - Exemple : bugfix/bug-1 diff --git a/docs/readme/readme_cn.md b/docs/readme/readme_cn.md index e9584c68ba..11852161bd 100644 --- a/docs/readme/readme_cn.md +++ b/docs/readme/readme_cn.md @@ -1,7 +1,7 @@
-### Bruno - 开源IDE,用于探索和测试API。 +### Bruno - 开源 IDE,用于探索和测试 API。 [![GitHub version](https://badge.fury.io/gh/usebruno%2Fbruno.svg)](https://badge.fury.io/gh/usebruno%bruno) [![CI](https://github.com/usebruno/bruno/actions/workflows/unit-tests.yml/badge.svg?branch=main)](https://github.com/usebruno/bruno/workflows/unit-tests.yml) @@ -12,16 +12,14 @@ [English](../../readme.md) | [Українська](./readme_ua.md) | [Русский](./readme_ru.md) | [Türkçe](./readme_tr.md) | [Deutsch](./readme_de.md) | [Français](./readme_fr.md) | [Português (BR)](./readme_pt_br.md) | [한국어](./readme_kr.md) | [বাংলা](./readme_bn.md) | [Español](./readme_es.md) | [Italiano](./readme_it.md) | [Română](./readme_ro.md) | [Polski](./readme_pl.md) | [简体中文](./readme_cn.md) - Bruno 是一款全新且创新的 API 客户端,旨在颠覆 Postman 和其他类似工具。 Bruno 直接在您的电脑文件夹中存储您的 API 信息。我们使用纯文本标记语言 Bru 来保存有关 API 的信息。 -您可以使用 Git 或您选择的任何版本控制系统来对您的API信息进行版本控制和协作。 +您可以使用 Git 或您选择的任何版本控制系统来对您的 API 信息进行版本控制和协作。 Bruno 仅限离线使用。我们计划永不向 Bruno 添加云同步功能。我们重视您的数据隐私,并认为它应该留在您的设备上。阅读我们的长期愿景 [点击查看](https://github.com/usebruno/bruno/discussions/269) - 📢 观看我们在印度 FOSS 3.0 会议上的最新演讲 [点击查看](https://www.youtube.com/watch?v=7bSMFpbcPiY) ![bruno](../../assets/images/landing-2.png)

@@ -97,9 +95,9 @@ sudo apt install bruno ### 贡献 👩‍💻🧑‍💻 -我很高兴您希望改进bruno。请查看 [贡献指南](../../contributing.md)。 +我很高兴您希望改进 bruno。请查看 [贡献指南](../../contributing.md)。 -即使您无法通过代码做出贡献,我们仍然欢迎您提出BUG和新的功能需求。 +即使您无法通过代码做出贡献,我们仍然欢迎您提出 BUG 和新的功能需求。 ### 作者 diff --git a/docs/readme/readme_fr.md b/docs/readme/readme_fr.md index aa7a6cafaa..dc470d597d 100644 --- a/docs/readme/readme_fr.md +++ b/docs/readme/readme_fr.md @@ -10,7 +10,6 @@ [![Website](https://img.shields.io/badge/Website-Visit-blue)](https://www.usebruno.com) [![Download](https://img.shields.io/badge/Download-Latest-brightgreen)](https://www.usebruno.com/downloads) - [English](/readme.md) | [Українська](docs/readme/readme_ua.md) | [Русский](docs/readme/readme_ru.md) | [Türkçe](docs/readme/readme_tr.md) | [Deutsch](docs/readme/readme_de.md) | **Français** | [Português (BR)](docs/readme/readme_pt_br.md) | [한국어](docs/readme/readme_kr.md) | [বাংলা](docs/readme/readme_bn.md) | [Español](docs/readme/readme_es.md) | [Italiano](docs/readme/readme_it.md) | [Română](docs/readme/readme_ro.md) | [Polski](docs/readme/readme_pl.md) Bruno est un nouveau client API, innovant, qui a pour but de révolutionner le _statu quo_ que représente Postman et les autres outils. @@ -21,9 +20,7 @@ Vous pouvez utiliser git ou tout autre gestionnaire de version pour travailler d Bruno ne fonctionne qu'en mode déconnecté. Il n'y a pas d'abonnement ou de synchronisation avec le cloud Bruno, il n'y en aura jamais. Nous sommes conscients de la confidentialité de vos données et nous sommes convaincus qu'elles doivent rester sur vos appareils. Vous pouvez lire notre vision à long terme [ici (en anglais)](https://github.com/usebruno/bruno/discussions/269). - -📢 Regarder notre présentation récente lors de la conférence India FOSS 3.0 (en anglais) [ici](https://www.youtube.com/watch?v=7bSMFpbcPiY) - +📢 Regarder notre présentation récente lors de la conférence India FOSS 3.0 (en anglais) [ici](https://www.youtube.com/watch?v=7bSMFpbcPiY) ![bruno](/assets/images/landing-2.png)

@@ -31,7 +28,7 @@ Bruno ne fonctionne qu'en mode déconnecté. Il n'y a pas d'abonnement ou de syn Bruno est disponible au téléchargement [sur notre site web](https://www.usebruno.com/downloads), pour Mac, Windows et Linux. -Vous pouvez aussi installer Bruno via un gestionnaire de paquets, comme Homebrew, Chocolatey, Scoop, Snap et Apt. +Vous pouvez aussi installer Bruno via un gestionnaire de paquets, comme Homebrew, Chocolatey, Scoop, Snap et Apt. ```sh # Mac via Homebrew diff --git a/package-lock.json b/package-lock.json index e225ab3b9a..3b57e938ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23949,14 +23949,6 @@ "mini-svg-data-uri": "^1.2.3" } }, - "@tailwindcss/forms": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", - "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", - "requires": { - "mini-svg-data-uri": "^1.2.3" - } - }, "@tippyjs/react": { "version": "4.2.6", "requires": { diff --git a/package.json b/package.json index f0acccdf9a..6b53669bb4 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "test:prettier:web": "npm run test:prettier --workspace=packages/bruno-app", "prepare": "husky install" }, - "overrides": { "rollup": "3.2.5" }, diff --git a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js index ee956f1b12..8f7d4835a8 100644 --- a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js +++ b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js @@ -114,7 +114,7 @@ const QueryResult = ({ item, collection, data, dataBuffer, width, disableRunEven {error ? (
-
{error}
+
{error}
{error && typeof error === 'string' && error.toLowerCase().includes('self signed certificate') ? (
diff --git a/packages/bruno-cli/readme.md b/packages/bruno-cli/readme.md index db41a4d7c2..274572e115 100644 --- a/packages/bruno-cli/readme.md +++ b/packages/bruno-cli/readme.md @@ -57,6 +57,7 @@ Thank you for using Bruno CLI! ## Changelog + See [https://github.com/usebruno/bruno/releases](https://github.com/usebruno/bruno/releases) ## License diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index ec4767efb6..017292fd74 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -8,7 +8,7 @@ const FormData = require('form-data'); const prepareRequest = require('./prepare-request'); const interpolateVars = require('./interpolate-vars'); const { interpolateString } = require('./interpolate-string'); -const { ScriptRuntime, TestRuntime, VarsRuntime, AssertRuntime } = require('@usebruno/js'); +const { ScriptRuntime, TestRuntime, VarsRuntime, AssertRuntime, runScript } = require('@usebruno/js'); const { stripExtension } = require('../utils/filesystem'); const { getOptions } = require('../utils/bru'); const https = require('https'); @@ -72,21 +72,41 @@ const runSingleRequest = async function ( get(collectionRoot, 'request.script.req'), get(bruJson, 'request.script.req') ]).join(os.EOL); - if (requestScriptFile?.length) { - const scriptRuntime = new ScriptRuntime(); - const result = await scriptRuntime.runRequestScript( + if (scriptingConfig?.runtime === 'node') { + const result = await runScript( decomment(requestScriptFile), request, - envVariables, - collectionVariables, - collectionPath, null, - processEnvVars, - scriptingConfig + { + envVariables, + collectionVariables, + processEnvVars + }, + false, + collectionPath, + scriptingConfig, + null ); if (result?.nextRequestName !== undefined) { nextRequestName = result.nextRequestName; } + } else { + if (requestScriptFile?.length) { + const scriptRuntime = new ScriptRuntime(); + const result = await scriptRuntime.runRequestScript( + decomment(requestScriptFile), + request, + envVariables, + collectionVariables, + collectionPath, + null, + processEnvVars, + scriptingConfig + ); + if (result?.nextRequestName !== undefined) { + nextRequestName = result.nextRequestName; + } + } } // interpolate variables inside request @@ -276,22 +296,42 @@ const runSingleRequest = async function ( get(collectionRoot, 'request.script.res'), get(bruJson, 'request.script.res') ]).join(os.EOL); - if (responseScriptFile?.length) { - const scriptRuntime = new ScriptRuntime(); - const result = await scriptRuntime.runResponseScript( + if (scriptingConfig?.runtime === 'node') { + const result = await runScript( decomment(responseScriptFile), request, response, - envVariables, - collectionVariables, + { + envVariables, + collectionVariables, + processEnvVars + }, + false, collectionPath, - null, - processEnvVars, - scriptingConfig + scriptingConfig, + null ); if (result?.nextRequestName !== undefined) { nextRequestName = result.nextRequestName; } + } else { + if (responseScriptFile?.length) { + const scriptRuntime = new ScriptRuntime(); + const result = await scriptRuntime.runResponseScript( + decomment(responseScriptFile), + request, + response, + envVariables, + collectionVariables, + collectionPath, + null, + processEnvVars, + scriptingConfig + ); + if (result?.nextRequestName !== undefined) { + nextRequestName = result.nextRequestName; + } + } } // run assertions @@ -321,20 +361,39 @@ const runSingleRequest = async function ( // run tests let testResults = []; const testFile = compact([get(collectionRoot, 'request.tests'), get(bruJson, 'request.tests')]).join(os.EOL); - if (typeof testFile === 'string') { - const testRuntime = new TestRuntime(); - const result = await testRuntime.runTests( + + if (scriptingConfig?.runtime === 'node') { + const result = await runScript( decomment(testFile), request, response, - envVariables, - collectionVariables, + { + envVariables, + collectionVariables, + processEnvVars + }, + true, collectionPath, - null, - processEnvVars, - scriptingConfig + scriptingConfig, + null ); testResults = get(result, 'results', []); + } else { + if (typeof testFile === 'string') { + const testRuntime = new TestRuntime(); + const result = await testRuntime.runTests( + decomment(testFile), + request, + response, + envVariables, + collectionVariables, + collectionPath, + null, + processEnvVars, + scriptingConfig + ); + testResults = get(result, 'results', []); + } } if (testResults?.length) { diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 73d8a59232..d72e98f2f7 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -11,7 +11,7 @@ const contentDispositionParser = require('content-disposition'); const mime = require('mime-types'); const { ipcMain } = require('electron'); const { isUndefined, isNull, each, get, compact, cloneDeep } = require('lodash'); -const { VarsRuntime, AssertRuntime, ScriptRuntime, TestRuntime } = require('@usebruno/js'); +const { VarsRuntime, AssertRuntime, ScriptRuntime, TestRuntime, runScript } = require('@usebruno/js'); const prepareRequest = require('./prepare-request'); const prepareCollectionRequest = require('./prepare-collection-request'); const prepareGqlIntrospectionRequest = require('./prepare-gql-introspection-request'); @@ -272,13 +272,17 @@ const parseDataFromResponse = (response) => { }; const registerNetworkIpc = (mainWindow) => { - const onConsoleLog = (type, args) => { + const onConsoleLog = async (type, args) => { console[type](...args); - mainWindow.webContents.send('main:console-log', { - type, - args - }); + try { + await mainWindow.webContents.send('main:console-log', { + type, + args + }); + } catch (e) { + console.error(`Could not send the above console.log to the BrowserWindow: "${e}"`); + } }; const runPreRequest = async ( @@ -318,27 +322,44 @@ const registerNetworkIpc = (mainWindow) => { // run pre-request script let scriptResult; const requestScript = compact([get(collectionRoot, 'request.script.req'), get(request, 'script.req')]).join(os.EOL); - if (requestScript?.length) { - const scriptRuntime = new ScriptRuntime(); - scriptResult = await scriptRuntime.runRequestScript( + if (scriptingConfig?.runtime === 'node') { + scriptResult = await runScript( decomment(requestScript), request, - envVars, - collectionVariables, + null, + { + envVariables: envVars, + collectionVariables, + processEnvVars + }, + false, collectionPath, - onConsoleLog, - processEnvVars, - scriptingConfig + scriptingConfig, + onConsoleLog ); - - mainWindow.webContents.send('main:script-environment-update', { - envVariables: scriptResult.envVariables, - collectionVariables: scriptResult.collectionVariables, - requestUid, - collectionUid - }); + } else { + if (requestScript?.length) { + const scriptRuntime = new ScriptRuntime(); + scriptResult = await scriptRuntime.runRequestScript( + decomment(requestScript), + request, + envVars, + collectionVariables, + collectionPath, + onConsoleLog, + processEnvVars, + scriptingConfig + ); + } } + mainWindow.webContents.send('main:script-environment-update', { + envVariables: scriptResult.envVariables, + collectionVariables: scriptResult.collectionVariables, + requestUid, + collectionUid + }); + // interpolate variables inside request interpolateVars(request, envVars, collectionVariables, processEnvVars); @@ -397,26 +418,49 @@ const registerNetworkIpc = (mainWindow) => { const responseScript = compact([get(collectionRoot, 'request.script.res'), get(request, 'script.res')]).join( os.EOL ); - if (responseScript?.length) { - const scriptRuntime = new ScriptRuntime(); - scriptResult = await scriptRuntime.runResponseScript( + + if (scriptingConfig?.runtime === 'node') { + scriptResult = await runScript( decomment(responseScript), request, response, - envVars, - collectionVariables, + { + envVariables: envVars, + collectionVariables, + processEnvVars + }, + false, collectionPath, - onConsoleLog, - processEnvVars, - scriptingConfig + scriptingConfig, + onConsoleLog ); - mainWindow.webContents.send('main:script-environment-update', { envVariables: scriptResult.envVariables, collectionVariables: scriptResult.collectionVariables, requestUid, collectionUid }); + } else { + if (responseScript?.length) { + const scriptRuntime = new ScriptRuntime(); + scriptResult = await scriptRuntime.runResponseScript( + decomment(responseScript), + request, + response, + envVars, + collectionVariables, + collectionPath, + onConsoleLog, + processEnvVars, + scriptingConfig + ); + mainWindow.webContents.send('main:script-environment-update', { + envVariables: scriptResult.envVariables, + collectionVariables: scriptResult.collectionVariables, + requestUid, + collectionUid + }); + } } return scriptResult; }; @@ -583,18 +627,36 @@ const registerNetworkIpc = (mainWindow) => { item.draft ? get(item.draft, 'request.tests') : get(item, 'request.tests') ]).join(os.EOL); if (typeof testFile === 'string') { - const testRuntime = new TestRuntime(); - const testResults = await testRuntime.runTests( - decomment(testFile), - request, - response, - envVars, - collectionVariables, - collectionPath, - onConsoleLog, - processEnvVars, - scriptingConfig - ); + let testResults; + if (scriptingConfig?.runtime === 'node') { + testResults = await runScript( + decomment(testFile), + request, + response, + { + envVariables: envVars, + collectionVariables, + processEnvVars + }, + true, + collectionPath, + scriptingConfig, + onConsoleLog + ); + } else { + const testRuntime = new TestRuntime(); + testResults = await testRuntime.runTests( + decomment(testFile), + request, + response, + envVars, + collectionVariables, + collectionPath, + onConsoleLog, + processEnvVars, + scriptingConfig + ); + } mainWindow.webContents.send('main:run-request-event', { type: 'test-results', @@ -1021,18 +1083,36 @@ const registerNetworkIpc = (mainWindow) => { item.draft ? get(item.draft, 'request.tests') : get(item, 'request.tests') ]).join(os.EOL); if (typeof testFile === 'string') { - const testRuntime = new TestRuntime(); - const testResults = await testRuntime.runTests( - decomment(testFile), - request, - response, - envVars, - collectionVariables, - collectionPath, - onConsoleLog, - processEnvVars, - scriptingConfig - ); + let testResults; + if (scriptingConfig?.runtime === 'node') { + testResults = await runScript( + decomment(testFile), + request, + response, + { + envVariables: envVars, + collectionVariables, + processEnvVars + }, + true, + collectionPath, + scriptingConfig, + onConsoleLog + ); + } else { + const testRuntime = new TestRuntime(); + testResults = await testRuntime.runTests( + decomment(testFile), + request, + response, + envVars, + collectionVariables, + collectionPath, + onConsoleLog, + processEnvVars, + scriptingConfig + ); + } mainWindow.webContents.send('main:run-folder-event', { type: 'test-results', diff --git a/packages/bruno-js/src/index.js b/packages/bruno-js/src/index.js index fe6447cfb3..b051869670 100644 --- a/packages/bruno-js/src/index.js +++ b/packages/bruno-js/src/index.js @@ -2,10 +2,12 @@ const ScriptRuntime = require('./runtime/script-runtime'); const TestRuntime = require('./runtime/test-runtime'); const VarsRuntime = require('./runtime/vars-runtime'); const AssertRuntime = require('./runtime/assert-runtime'); +const { runScript } = require('./runtime/vm-helper'); module.exports = { ScriptRuntime, TestRuntime, VarsRuntime, - AssertRuntime + AssertRuntime, + runScript }; diff --git a/packages/bruno-js/src/runtime/vm-helper.js b/packages/bruno-js/src/runtime/vm-helper.js new file mode 100644 index 0000000000..522a5d9fb0 --- /dev/null +++ b/packages/bruno-js/src/runtime/vm-helper.js @@ -0,0 +1,246 @@ +const vm = require('node:vm'); +const Bru = require('../bru'); +const BrunoRequest = require('../bruno-request'); +const { get } = require('lodash'); +const lodash = require('lodash'); +const path = require('path'); +const { cleanJson } = require('../utils'); +const chai = require('chai'); +const BrunoResponse = require('../bruno-response'); +const TestResults = require('../test-results'); +const Test = require('../test'); + +/** + * @param {string} script + * @param {object} request + * @param {object|null} response + * @param {{ + * envVariables: Record, + * collectionVariables: Record, + * processEnvVars: Record, + * }} variables + * @param {boolean} useTests + * @param {string} collectionPath + * @param {object} scriptingConfig + * @param {(type: string, context: any) => void} onConsoleLog + * + * @returns {Promise<{ + * collectionVariables: Record, + * envVariables: Record, + * nextRequestName: string, + * results: array|null, + * }>} + */ +async function runScript( + script, + request, + response, + variables, + useTests, + collectionPath, + scriptingConfig, + onConsoleLog +) { + const scriptContext = buildScriptContext( + request, + response, + variables, + useTests, + collectionPath, + scriptingConfig, + onConsoleLog + ); + + if (script.trim().length !== 0) { + await vm.runInThisContext(` + (async ({ require, console, req, res, bru, expect, assert, test }) => { + ${script} + }); + `)(scriptContext); + } + + return { + envVariables: cleanJson(scriptContext.bru.envVariables), + collectionVariables: cleanJson(scriptContext.bru.collectionVariables), + nextRequestName: scriptContext.bru.nextRequest, + results: scriptContext.__brunoTestResults ? cleanJson(scriptContext.__brunoTestResults.getResults()) : null + }; +} + +/** + * @typedef {{ + * require: (module: string) => (*), + * console: {object}, + * req: {BrunoRequest}, + * res: {BrunoResponse}, + * bru: {Bru}, + * expect: {ExpectStatic}, + * assert: {AssertStatic}, + * __brunoTestResults: {object}, + * test: {Test}, + * }} ScriptContext + * + * @param {object} request + * @param {object|null} response + * @param {{ + * envVariables: Record, + * collectionVariables: Record, + * processEnvVars: Record, + * }} variables + * @param {boolean} useTests + * @param {string} collectionPath + * @param {object} scriptingConfig + * @param {(type: string, context: any) => void} onConsoleLog + * + * @return {ScriptContext} + */ +function buildScriptContext(request, response, variables, useTests, collectionPath, scriptingConfig, onConsoleLog) { + const context = { + require: createCustomRequire(scriptingConfig, collectionPath), + console: createCustomConsole(onConsoleLog), + req: new BrunoRequest(request), + res: null, + bru: new Bru(variables.envVariables, variables.collectionVariables, variables.processEnvVars, collectionPath), + expect: null, + assert: null, + __brunoTestResults: null, + test: null + }; + + if (response) { + context.res = new BrunoResponse(response); + } + + if (useTests) { + Object.assign(context, createTestContext()); + } + + return context; +} + +const defaultModuleWhiteList = [ + // Node libs + 'path', + 'stream', + 'util', + 'url', + 'http', + 'https', + 'punycode', + 'zlib', + // Pre-installed 3rd libs + 'ajv', + 'atob', + 'btoa', + 'lodash', + 'moment', + 'uuid', + 'nanoid', + 'axios', + 'chai', + 'crypto-js', + 'node-vault', + 'node-fetch' +]; + +/** + * @param {object} scriptingConfig Config from collection's bruno.json + * @param {string} collectionPath + * + * @returns {(module: string) => (*)} + */ +function createCustomRequire(scriptingConfig, collectionPath) { + const customWhitelistedModules = get(scriptingConfig, 'moduleWhitelist', []); + + const whitelistedModules = [...defaultModuleWhiteList, ...customWhitelistedModules]; + + const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false); + if (allowScriptFilesystemAccess) { + whitelistedModules.push('fs'); + } + + const additionalContextRoots = get(scriptingConfig, 'additionalContextRoots', []); + const additionalContextRootsAbsolute = lodash + .chain(additionalContextRoots) + .map((acr) => (acr.startsWith('/') ? acr : path.join(collectionPath, acr))) + .value(); + additionalContextRootsAbsolute.push(collectionPath); + + return (moduleName) => { + // First check If we want to require a native node module or an internal node module + // Remove the "node:" prefix, to make sure "node:fs" and "fs" can be required, and we only need to whitelist one + if (whitelistedModules.includes(moduleName.replace(/^node:/, ''))) { + try { + return require(moduleName); + } catch { + // This can happen, if it s module installed by the user under additionalContextRoots + // So now we check if the user installed it themselves + let modulePath; + try { + modulePath = require.resolve(moduleName, { paths: additionalContextRootsAbsolute }); + return require(modulePath); + } catch (error) { + throw new Error(`Could not resolve module "${moduleName}": ${error} + This most likely means you did not install the module under "additionalContextRoots" using a package manger like npm. + + These are your current "additionalContextRoots": + - ${additionalContextRootsAbsolute.join('- ') || 'No "additionalContextRoots" defined'} + `); + } + } + } + + const triedPaths = []; + for (const contextRoot of additionalContextRootsAbsolute) { + const fullScriptPath = path.join(contextRoot, moduleName); + try { + return require(fullScriptPath); + } catch { + triedPaths.push({ fullScriptPath }); + } + } + + const triedPathsFormatted = triedPaths.map((i) => `- ${i.fullScriptPath}\n`); + throw new Error(`Failed to require "${moduleName}"! + +If you tried to require a internal node module / external package, make sure its whitelisted in the "bruno.json" under "scriptConfig". +If you wanted to require an external script make sure the path is correct or added to "additionalContextRoots" in your "bruno.json". + +${ + triedPathsFormatted.length === 0 + ? 'No additional context roots where defined' + : 'We searched the following paths for your script:' +} +${triedPathsFormatted}`); + }; +} + +function createCustomConsole(onConsoleLog) { + const customLogger = (type) => { + return (...args) => { + onConsoleLog && onConsoleLog(type, cleanJson(args)); + }; + }; + return { + log: customLogger('log'), + info: customLogger('info'), + warn: customLogger('warn'), + error: customLogger('error') + }; +} + +function createTestContext() { + const __brunoTestResults = new TestResults(); + const test = Test(__brunoTestResults, chai); + + return { + test, + __brunoTestResults, + expect: chai.expect, + assert: chai.assert + }; +} + +module.exports = { + runScript +};