mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-23 20:55:41 +00:00
feat: updated the bru async parsing logic (#3898)
This commit is contained in:
@@ -28,26 +28,28 @@ const RequestNotLoaded = ({ collection, item }) => {
|
||||
<div>{item?.pathname}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col gap-6 w-fit justify-start'>
|
||||
<div className='flex flex-col'>
|
||||
<button className={`submit btn btn-sm btn-secondary w-fit h-fit flex flex-row gap-2 ${item?.loading? 'opacity-50 cursor-blocked': ''}`} onClick={handleLoadRequestSync}>
|
||||
{item?.loading ? `Loading Request` : `Load Request`}
|
||||
{item?.loading ? <IconLoader2 className="animate-spin" size={18} strokeWidth={1.5} /> : null}
|
||||
</button>
|
||||
<small className='text-muted mt-1'>
|
||||
May cause the app to freeze temporarily while it runs.
|
||||
</small>
|
||||
{!item?.error ?
|
||||
<div className='flex flex-col gap-6 w-fit justify-start'>
|
||||
<div className='flex flex-col'>
|
||||
<button className={`submit btn btn-sm btn-secondary w-fit h-fit flex flex-row gap-2 ${item?.loading? 'opacity-50 cursor-blocked': ''}`} onClick={handleLoadRequestSync}>
|
||||
{item?.loading ? `Loading Request` : `Load Request`}
|
||||
{item?.loading ? <IconLoader2 className="animate-spin" size={18} strokeWidth={1.5} /> : null}
|
||||
</button>
|
||||
<small className='text-muted mt-1'>
|
||||
May cause the app to freeze temporarily while it runs.
|
||||
</small>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<button className={`submit btn btn-sm btn-secondary w-fit h-fit flex flex-row gap-2 ${item?.loading? 'opacity-50 cursor-blocked': ''}`} onClick={handleLoadRequest}>
|
||||
{item?.loading ? `Loading Request` : `Load Request in Background`}
|
||||
{item?.loading ? <IconLoader2 className="animate-spin" size={18} strokeWidth={1.5} /> : null}
|
||||
</button>
|
||||
<small className='text-muted mt-1'>
|
||||
Runs in background.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col'>
|
||||
<button className={`submit btn btn-sm btn-secondary w-fit h-fit flex flex-row gap-2 ${item?.loading? 'opacity-50 cursor-blocked': ''}`} onClick={handleLoadRequest}>
|
||||
{item?.loading ? `Loading Request` : `Load Request in Background`}
|
||||
{item?.loading ? <IconLoader2 className="animate-spin" size={18} strokeWidth={1.5} /> : null}
|
||||
</button>
|
||||
<small className='text-muted mt-1'>
|
||||
Runs in background.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
: null}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { IconRefresh, IconCircleCheck, IconCircleX, IconCheck, IconX, IconRun }
|
||||
import slash from 'utils/common/slash';
|
||||
import ResponsePane from './ResponsePane';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { areItemsLoading } from 'utils/collections/index';
|
||||
|
||||
const getRelativePath = (fullPath, pathname) => {
|
||||
// convert to unix style path
|
||||
@@ -106,6 +107,8 @@ export default function RunnerResults({ collection }) {
|
||||
return (item.status !== 'error' && item.testStatus === 'fail') || item.assertionStatus === 'fail';
|
||||
});
|
||||
|
||||
let isCollectionLoading = areItemsLoading(collection);
|
||||
|
||||
if (!items || !items.length) {
|
||||
return (
|
||||
<StyledWrapper className="px-4 pb-4">
|
||||
@@ -116,7 +119,7 @@ export default function RunnerResults({ collection }) {
|
||||
<div className="mt-6">
|
||||
You have <span className="font-medium">{totalRequestsInCollection}</span> requests in this collection.
|
||||
</div>
|
||||
|
||||
{isCollectionLoading ? <div className='my-1 danger'>Requests in this collection are still loading.</div> : null}
|
||||
<div className="mt-6">
|
||||
<label>Delay (in ms)</label>
|
||||
<input
|
||||
|
||||
@@ -4,6 +4,9 @@ const Wrapper = styled.div`
|
||||
.partial {
|
||||
color: ${(props) => props.theme.colors.text.yellow};
|
||||
}
|
||||
.error {
|
||||
color: ${(props) => props.theme.colors.text.danger};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import RequestMethod from "../RequestMethod";
|
||||
import { IconLoader2, IconAlertTriangle } from '@tabler/icons';
|
||||
import { IconLoader2, IconAlertTriangle, IconAlertCircle } from '@tabler/icons';
|
||||
import StyledWrapper from "./StyledWrapper";
|
||||
|
||||
const CollectionItemIcon = ({ item }) => {
|
||||
if (item?.error) {
|
||||
return <StyledWrapper><IconAlertCircle className="w-fit mr-2 error" size={18} strokeWidth={1.5} /></StyledWrapper>;
|
||||
}
|
||||
|
||||
if (item?.loading) {
|
||||
return <IconLoader2 className="animate-spin w-fit mr-2" size={18} strokeWidth={1.5} />;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ const Wrapper = styled.div`
|
||||
.bruno-modal-content {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.warning {
|
||||
color: ${(props) => props.theme.colors.text.danger};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { addTab } from 'providers/ReduxStore/slices/tabs';
|
||||
import { runCollectionFolder } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { flattenItems } from 'utils/collections';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
import { areItemsLoading } from 'utils/collections/index';
|
||||
|
||||
const RunCollectionItem = ({ collection, item, onClose }) => {
|
||||
const dispatch = useDispatch();
|
||||
@@ -32,6 +33,8 @@ const RunCollectionItem = ({ collection, item, onClose }) => {
|
||||
const flattenedItems = flattenItems(item ? item.items : collection.items);
|
||||
const recursiveRunLength = getRequestsCount(flattenedItems);
|
||||
|
||||
const isFolderLoading = areItemsLoading(item);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<Modal size="md" title="Collection Runner" hideFooter={true} handleCancel={onClose}>
|
||||
@@ -44,13 +47,12 @@ const RunCollectionItem = ({ collection, item, onClose }) => {
|
||||
<span className="ml-1 text-xs">({runLength} requests)</span>
|
||||
</div>
|
||||
<div className="mb-8">This will only run the requests in this folder.</div>
|
||||
|
||||
<div className="mb-1">
|
||||
<span className="font-medium">Recursive Run</span>
|
||||
<span className="ml-1 text-xs">({recursiveRunLength} requests)</span>
|
||||
</div>
|
||||
<div className="mb-8">This will run all the requests in this folder and all its subfolders.</div>
|
||||
|
||||
<div className={isFolderLoading ? "mb-2" : "mb-8"}>This will run all the requests in this folder and all its subfolders.</div>
|
||||
{isFolderLoading ? <div className='mb-8 warning'>Requests in this folder are still loading.</div> : null}
|
||||
<div className="flex justify-end bruno-modal-footer">
|
||||
<span className="mr-3">
|
||||
<button type="button" onClick={onClose} className="btn btn-md btn-close">
|
||||
|
||||
@@ -1196,7 +1196,6 @@ export const hydrateCollectionWithUiStateSnapshot = (payload) => (dispatch, getS
|
||||
export const loadRequest = ({ collectionUid, pathname }) => (dispatch, getState) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const { ipcRenderer } = window;
|
||||
ipcRenderer.invoke('renderer:load-request-init', { collectionUid, pathname }).then(resolve).catch(reject);
|
||||
ipcRenderer.invoke('renderer:load-request', { collectionUid, pathname }).then(resolve).catch(reject);
|
||||
});
|
||||
};
|
||||
@@ -1204,7 +1203,6 @@ export const loadRequest = ({ collectionUid, pathname }) => (dispatch, getState)
|
||||
export const loadRequestSync = ({ collectionUid, pathname }) => (dispatch, getState) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const { ipcRenderer } = window;
|
||||
ipcRenderer.invoke('renderer:load-request-init', { collectionUid, pathname }).then(resolve).catch(reject);
|
||||
ipcRenderer.invoke('renderer:load-request-sync', { collectionUid, pathname }).then(resolve).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1617,6 +1617,7 @@ export const collectionsSlice = createSlice({
|
||||
currentItem.partial = file.partial;
|
||||
currentItem.loading = file.loading;
|
||||
currentItem.size = file.size;
|
||||
currentItem.error = file.error;
|
||||
} else {
|
||||
currentSubItems.push({
|
||||
uid: file.data.uid,
|
||||
@@ -1629,7 +1630,8 @@ export const collectionsSlice = createSlice({
|
||||
draft: null,
|
||||
partial: file.partial,
|
||||
loading: file.loading,
|
||||
size: file.size
|
||||
size: file.size,
|
||||
error: file.error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const chokidar = require('chokidar');
|
||||
const { hasBruExtension, isWSLPath, normalizeAndResolvePath, normalizeWslPath, sizeInMB } = require('../utils/filesystem');
|
||||
const { bruToEnvJson, bruToJson, collectionBruToJson, bruToJsonViaWorker, collectionBruToJsonViaWorker } = require('../bru');
|
||||
const { bruToEnvJson, bruToJson, bruToJsonViaWorker ,collectionBruToJson } = require('../bru');
|
||||
const { dotenvToJson } = require('@usebruno/lang');
|
||||
|
||||
const { uuid } = require('../utils/common');
|
||||
@@ -259,7 +259,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
// If worker thread is not used, we can directly parse the file
|
||||
if (!useWorkerThread) {
|
||||
try {
|
||||
file.data = bruToJson(bruContent);
|
||||
file.data = await bruToJson(bruContent);
|
||||
file.partial = false;
|
||||
file.loading = false;
|
||||
file.size = sizeInMB(fileStats?.size);
|
||||
@@ -278,15 +278,22 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
name: path.basename(pathname),
|
||||
type: 'http-request'
|
||||
};
|
||||
|
||||
const metaJson = await bruToJson(getBruFileMeta(bruContent), true);
|
||||
file.data = metaJson;
|
||||
file.partial = true;
|
||||
file.loading = false;
|
||||
file.size = sizeInMB(fileStats?.size);
|
||||
hydrateRequestWithUuid(file.data, pathname);
|
||||
win.webContents.send('main:collection-tree-updated', 'addFile', file);
|
||||
|
||||
// If the file is smaller than the max file size, we can parse the file
|
||||
// and send the full file info to the UI
|
||||
if (fileStats.size < MAX_FILE_SIZE) {
|
||||
file.data = metaJson;
|
||||
file.partial = false;
|
||||
file.loading = true;
|
||||
hydrateRequestWithUuid(file.data, pathname);
|
||||
win.webContents.send('main:collection-tree-updated', 'addFile', file);
|
||||
file.data = await bruToJsonViaWorker(bruContent);
|
||||
file.partial = false;
|
||||
file.loading = false;
|
||||
@@ -298,6 +305,9 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
name: path.basename(pathname),
|
||||
type: 'http-request'
|
||||
};
|
||||
file.error = {
|
||||
message: error?.message
|
||||
};
|
||||
file.partial = true;
|
||||
file.loading = false;
|
||||
file.size = sizeInMB(fileStats?.size);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const _ = require('lodash');
|
||||
const {
|
||||
bruToJsonV2,
|
||||
jsonToBruV2,
|
||||
bruToEnvJsonV2,
|
||||
envJsonToBruV2,
|
||||
collectionBruToJson: _collectionBruToJson,
|
||||
@@ -40,16 +41,6 @@ const collectionBruToJson = async (data, parsed = false) => {
|
||||
}
|
||||
};
|
||||
|
||||
const collectionBruToJsonViaWorker = async (bru) => {
|
||||
try {
|
||||
const json = await bruParserWorker?.collectionBruToJson(bru);
|
||||
|
||||
return collectionBruToJson(json);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const jsonToCollectionBru = async (json, isFolder) => {
|
||||
try {
|
||||
const collectionBruJson = {
|
||||
@@ -165,7 +156,6 @@ const bruToJson = (data, parsed = false) => {
|
||||
const bruToJsonViaWorker = async (data) => {
|
||||
try {
|
||||
const json = await bruParserWorker?.bruToJson(data);
|
||||
|
||||
return bruToJson(json, true);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
@@ -218,10 +208,52 @@ const jsonToBru = async (json) => {
|
||||
docs: _.get(json, 'request.docs', '')
|
||||
};
|
||||
|
||||
const bru = jsonToBruV2(bruJson);
|
||||
return bru;
|
||||
};
|
||||
|
||||
const jsonToBruViaWorker = async (json) => {
|
||||
let type = _.get(json, 'type');
|
||||
if (type === 'http-request') {
|
||||
type = 'http';
|
||||
} else if (type === 'graphql-request') {
|
||||
type = 'graphql';
|
||||
} else {
|
||||
type = 'http';
|
||||
}
|
||||
|
||||
const sequence = _.get(json, 'seq');
|
||||
const bruJson = {
|
||||
meta: {
|
||||
name: _.get(json, 'name'),
|
||||
type: type,
|
||||
seq: !isNaN(sequence) ? Number(sequence) : 1
|
||||
},
|
||||
http: {
|
||||
method: _.lowerCase(_.get(json, 'request.method')),
|
||||
url: _.get(json, 'request.url'),
|
||||
auth: _.get(json, 'request.auth.mode', 'none'),
|
||||
body: _.get(json, 'request.body.mode', 'none')
|
||||
},
|
||||
params: _.get(json, 'request.params', []),
|
||||
headers: _.get(json, 'request.headers', []),
|
||||
auth: _.get(json, 'request.auth', {}),
|
||||
body: _.get(json, 'request.body', {}),
|
||||
script: _.get(json, 'request.script', {}),
|
||||
vars: {
|
||||
req: _.get(json, 'request.vars.req', []),
|
||||
res: _.get(json, 'request.vars.res', [])
|
||||
},
|
||||
assertions: _.get(json, 'request.assertions', []),
|
||||
tests: _.get(json, 'request.tests', ''),
|
||||
docs: _.get(json, 'request.docs', '')
|
||||
};
|
||||
|
||||
const bru = await bruParserWorker?.jsonToBru(bruJson)
|
||||
return bru;
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
bruToJson,
|
||||
bruToJsonViaWorker,
|
||||
@@ -229,6 +261,6 @@ module.exports = {
|
||||
bruToEnvJson,
|
||||
envJsonToBru,
|
||||
collectionBruToJson,
|
||||
collectionBruToJsonViaWorker,
|
||||
jsonToCollectionBru
|
||||
jsonToCollectionBru,
|
||||
jsonToBruViaWorker
|
||||
};
|
||||
|
||||
@@ -49,8 +49,8 @@ class BruParserWorker {
|
||||
return this.enqueueTask({ data, scriptFile: `bru-to-json` });
|
||||
}
|
||||
|
||||
async collectionBruToJson(data) {
|
||||
return this.enqueueTask({ data, scriptFile: `collection-bru-to-json` });
|
||||
async jsonToBru(data) {
|
||||
return this.enqueueTask({ data, scriptFile: `json-to-bru` });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,4 +10,5 @@ try {
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
parentPort.postMessage({ error: error?.message });
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
const { workerData, parentPort } = require('worker_threads');
|
||||
const {
|
||||
collectionBruToJson,
|
||||
} = require('@usebruno/lang');
|
||||
|
||||
try {
|
||||
const bru = workerData;
|
||||
const json = collectionBruToJson(bru);
|
||||
parentPort.postMessage(json);
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
const { workerData, parentPort } = require('worker_threads');
|
||||
const {
|
||||
jsonToBruV2,
|
||||
} = require('@usebruno/lang');
|
||||
try {
|
||||
const json = workerData;
|
||||
const bru = jsonToBruV2(json);
|
||||
parentPort.postMessage(bru);
|
||||
}
|
||||
catch(error) {
|
||||
console.error(error);
|
||||
parentPort.postMessage({ error: error?.message });
|
||||
}
|
||||
@@ -4,7 +4,7 @@ const fsExtra = require('fs-extra');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { ipcMain, shell, dialog, app } = require('electron');
|
||||
const { envJsonToBru, bruToJson, jsonToBru, jsonToCollectionBru, bruToJsonViaWorker } = require('../bru');
|
||||
const { envJsonToBru, bruToJson, jsonToBruViaWorker, jsonToCollectionBru, bruToJsonViaWorker } = require('../bru');
|
||||
|
||||
const {
|
||||
isValidPathname,
|
||||
@@ -226,7 +226,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
if (!isValidFilename(request.name)) {
|
||||
throw new Error(`path: ${request.name}.bru is not a valid filename`);
|
||||
}
|
||||
const content = await jsonToBru(request);
|
||||
const content = await jsonToBruViaWorker(request);
|
||||
await writeFile(pathname, content);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
@@ -240,7 +240,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
throw new Error(`path: ${pathname} does not exist`);
|
||||
}
|
||||
|
||||
const content = await jsonToBru(request);
|
||||
const content = await jsonToBruViaWorker(request);
|
||||
await writeFile(pathname, content);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
@@ -258,7 +258,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
throw new Error(`path: ${pathname} does not exist`);
|
||||
}
|
||||
|
||||
const content = await jsonToBru(request);
|
||||
const content = await jsonToBruViaWorker(request);
|
||||
await writeFile(pathname, content);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -425,11 +425,11 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
|
||||
// update name in file and save new copy, then delete old copy
|
||||
const data = await fs.promises.readFile(oldPath, 'utf8'); // Use async read
|
||||
const jsonData = await bruToJson(data);
|
||||
const jsonData = await bruToJsonViaWorker(data);
|
||||
jsonData.name = newName;
|
||||
moveRequestUid(oldPath, newPath);
|
||||
|
||||
const content = await jsonToBru(jsonData);
|
||||
const content = await jsonToBruViaWorker(jsonData);
|
||||
await fs.promises.unlink(oldPath);
|
||||
await writeFile(newPath, content);
|
||||
|
||||
@@ -531,7 +531,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
const parseCollectionItems = (items = [], currentPath) => {
|
||||
items.forEach(async (item) => {
|
||||
if (['http-request', 'graphql-request'].includes(item.type)) {
|
||||
const content = await jsonToBru(item);
|
||||
const content = await jsonToBruViaWorker(item);
|
||||
const filePath = path.join(currentPath, `${item.name}.bru`);
|
||||
fs.writeFileSync(filePath, content);
|
||||
}
|
||||
@@ -626,7 +626,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
const parseCollectionItems = (items = [], currentPath) => {
|
||||
items.forEach(async (item) => {
|
||||
if (['http-request', 'graphql-request'].includes(item.type)) {
|
||||
const content = await jsonToBru(item);
|
||||
const content = await jsonToBruViaWorker(item);
|
||||
const filePath = path.join(currentPath, `${item.name}.bru`);
|
||||
fs.writeFileSync(filePath, content);
|
||||
}
|
||||
@@ -672,11 +672,11 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
try {
|
||||
for await (let item of itemsToResequence) {
|
||||
const bru = fs.readFileSync(item.pathname, 'utf8');
|
||||
const jsonData = await bruToJson(bru);
|
||||
const jsonData = await bruToJsonViaWorker(bru);
|
||||
|
||||
if (jsonData.seq !== item.seq) {
|
||||
jsonData.seq = item.seq;
|
||||
const content = await jsonToBru(jsonData);
|
||||
const content = await jsonToBruViaWorker(jsonData);
|
||||
await writeFile(item.pathname, content);
|
||||
}
|
||||
}
|
||||
@@ -792,7 +792,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('renderer:load-request-init', async (event, { collectionUid, pathname }) => {
|
||||
ipcMain.handle('renderer:load-request', async (event, { collectionUid, pathname }) => {
|
||||
let fileStats;
|
||||
try {
|
||||
fileStats = fs.statSync(pathname);
|
||||
@@ -812,26 +812,7 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
file.size = sizeInMB(fileStats?.size);
|
||||
hydrateRequestWithUuid(file.data, pathname);
|
||||
mainWindow.webContents.send('main:collection-tree-updated', 'addFile', file);
|
||||
}
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('renderer:load-request', async (event, { collectionUid, pathname }) => {
|
||||
let fileStats;
|
||||
try {
|
||||
fileStats = fs.statSync(pathname);
|
||||
if (hasBruExtension(pathname)) {
|
||||
const file = {
|
||||
meta: {
|
||||
collectionUid,
|
||||
pathname,
|
||||
name: path.basename(pathname)
|
||||
}
|
||||
};
|
||||
let bruContent = fs.readFileSync(pathname, 'utf8');
|
||||
file.data = await bruToJson(bruContent);
|
||||
file.data = await bruToJsonViaWorker(bruContent);
|
||||
file.partial = false;
|
||||
file.loading = true;
|
||||
file.size = sizeInMB(fileStats?.size);
|
||||
@@ -873,6 +854,13 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
|
||||
}
|
||||
};
|
||||
let bruContent = fs.readFileSync(pathname, 'utf8');
|
||||
const metaJson = await bruToJson(getBruFileMeta(bruContent), true);
|
||||
file.data = metaJson;
|
||||
file.loading = true;
|
||||
file.partial = true;
|
||||
file.size = sizeInMB(fileStats?.size);
|
||||
hydrateRequestWithUuid(file.data, pathname);
|
||||
mainWindow.webContents.send('main:collection-tree-updated', 'addFile', file);
|
||||
file.data = bruToJson(bruContent);
|
||||
file.partial = false;
|
||||
file.loading = true;
|
||||
|
||||
@@ -210,7 +210,7 @@ const getTreePathFromCollectionToItem = (collection, _item) => {
|
||||
const getBruFileMeta = (data) => {
|
||||
try {
|
||||
const metaRegex = /meta\s*{\s*([\s\S]*?)\s*}/;
|
||||
const match = data.match(metaRegex);
|
||||
const match = data?.match?.(metaRegex);
|
||||
if (match) {
|
||||
const metaContent = match[1].trim();
|
||||
const lines = metaContent.replace(/\r\n/g, '\n').split('\n');
|
||||
|
||||
@@ -39,6 +39,9 @@ class WorkerQueue {
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker(scriptPath, { workerData: data });
|
||||
worker.on('message', (data) => {
|
||||
if (data?.error) {
|
||||
reject(new Error(data?.error));
|
||||
}
|
||||
resolve(data);
|
||||
worker.terminate();
|
||||
});
|
||||
|
||||
121
packages/bruno-electron/tests/utils/collection.spec.js
Normal file
121
packages/bruno-electron/tests/utils/collection.spec.js
Normal file
@@ -0,0 +1,121 @@
|
||||
const { getBruFileMeta } = require("../../src/utils/collection");
|
||||
|
||||
describe('getBruFileMeta', () => {
|
||||
test('parses valid meta block correctly', () => {
|
||||
const data = `meta {
|
||||
name: 0.2_mb
|
||||
type: http
|
||||
seq: 1
|
||||
}`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
meta: {
|
||||
name: '0.2_mb',
|
||||
type: 'http',
|
||||
seq: 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('returns undefined for missing meta block', () => {
|
||||
const data = `someOtherBlock {
|
||||
key: value
|
||||
}`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
test('handles empty meta block gracefully', () => {
|
||||
const data = `meta {}`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toEqual({ meta: {} });
|
||||
});
|
||||
|
||||
test('ignores invalid lines in meta block', () => {
|
||||
const data = `meta {
|
||||
name: 0.2_mb
|
||||
invalidLine
|
||||
seq: 1
|
||||
}`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
meta: {
|
||||
name: '0.2_mb',
|
||||
seq: 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('handles unexpected input gracefully', () => {
|
||||
const data = null;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
test('handles missing colon gracefully', () => {
|
||||
const data = `meta {
|
||||
name 0.2_mb
|
||||
seq: 1
|
||||
}`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
meta: {
|
||||
seq: 1,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('parses numeric values correctly', () => {
|
||||
const data = `meta {
|
||||
numValue: 1234
|
||||
floatValue: 12.34
|
||||
strValue: some_text
|
||||
}`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
meta: {
|
||||
numValue: 1234,
|
||||
floatValue: 12.34,
|
||||
strValue: 'some_text',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('handles syntax error in meta block 1', () => {
|
||||
const data = `meta
|
||||
name: 0.2_mb
|
||||
type: http
|
||||
seq: 1
|
||||
}`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
test('handles syntax error in meta block 2', () => {
|
||||
const data = `meta {
|
||||
name: 0.2_mb
|
||||
type: http
|
||||
seq: 1
|
||||
`;
|
||||
|
||||
const result = getBruFileMeta(data);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user