wip: abstracting parse and stringify operations

This commit is contained in:
Anoop M D
2025-02-07 14:44:27 +05:30
parent 0b19b26ce7
commit 17365b0d63
6 changed files with 224 additions and 160 deletions

View File

@@ -5,6 +5,16 @@ const chokidar = require('chokidar');
const { hasBruExtension, isWSLPath, normalizeAndResolvePath, normalizeWslPath, sizeInMB } = require('../utils/filesystem');
const { bruToEnvJson, bruToJson, bruToJsonViaWorker ,collectionBruToJson } = require('../bru');
const { dotenvToJson } = require('@usebruno/lang');
const {
parseRequest,
stringifyRequest,
parseCollection,
stringifyCollection,
parseFolder,
stringifyFolder,
parseEnvironment,
stringifyEnvironment
} = require('../filestore');
const { uuid } = require('../utils/common');
const { getRequestUid } = require('../cache/requestUids');
@@ -80,7 +90,7 @@ const addEnvironmentFile = async (win, pathname, collectionUid, collectionPath)
let bruContent = fs.readFileSync(pathname, 'utf8');
file.data = await bruToEnvJson(bruContent);
file.data = await parseEnvironment(bruContent, { format: 'bru' });
file.data.name = basename.substring(0, basename.length - 4);
file.data.uid = getRequestUid(pathname);
@@ -209,8 +219,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
try {
let bruContent = fs.readFileSync(pathname, 'utf8');
file.data = await collectionBruToJson(bruContent);
file.data = await parseCollection(bruContent, { format: 'bru' });
hydrateBruCollectionFileWithUuid(file.data);
win.webContents.send('main:collection-tree-updated', 'addFile', file);
return;
@@ -234,8 +243,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
try {
let bruContent = fs.readFileSync(pathname, 'utf8');
file.data = await collectionBruToJson(bruContent);
file.data = await parseFolder(bruContent, { format: 'bru' });
hydrateBruCollectionFileWithUuid(file.data);
win.webContents.send('main:collection-tree-updated', 'addFile', file);
return;
@@ -259,7 +267,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 = await bruToJson(bruContent);
file.data = await parseRequest(bruContent, { format: 'bru' });
file.partial = false;
file.loading = false;
file.size = sizeInMB(fileStats?.size);
@@ -279,7 +287,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
type: 'http-request'
};
const metaJson = await bruToJson(parseBruFileMeta(bruContent), true);
const metaJson = await parseRequest(parseBruFileMeta(bruContent), { format: 'bru' });
file.data = metaJson;
file.partial = true;
file.loading = false;
@@ -296,7 +304,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
win.webContents.send('main:collection-tree-updated', 'addFile', file);
// This is to update the file info in the UI
file.data = await bruToJsonViaWorker(bruContent);
file.data = await parseRequest(bruContent, { format: 'bru', useWorker: true });
file.partial = false;
file.loading = false;
hydrateRequestWithUuid(file.data, pathname);

View File

@@ -4,116 +4,31 @@ const {
jsonToBruV2,
bruToEnvJsonV2,
envJsonToBruV2,
collectionBruToJson: _collectionBruToJson,
jsonToCollectionBru: _jsonToCollectionBru
collectionBruToJson,
jsonToCollectionBru
} = require('@usebruno/lang');
const BruParserWorker = require('./workers');
const bruParserWorker = new BruParserWorker();
const collectionBruToJson = async (data, parsed = false) => {
try {
const json = parsed ? data : _collectionBruToJson(data);
const transformedJson = {
request: {
headers: _.get(json, 'headers', []),
auth: _.get(json, 'auth', {}),
script: _.get(json, 'script', {}),
vars: _.get(json, 'vars', {}),
tests: _.get(json, 'tests', '')
},
docs: _.get(json, 'docs', '')
};
// add meta if it exists
// this is only for folder bru file
// in the future, all of this will be replaced by standard bru lang
if (json.meta) {
transformedJson.meta = {
name: json.meta.name
};
}
return transformedJson;
} catch (error) {
return Promise.reject(error);
}
};
const jsonToCollectionBru = async (json, isFolder) => {
try {
const collectionBruJson = {
headers: _.get(json, 'request.headers', []),
script: {
req: _.get(json, 'request.script.req', ''),
res: _.get(json, 'request.script.res', '')
},
vars: {
req: _.get(json, 'request.vars.req', []),
res: _.get(json, 'request.vars.res', [])
},
tests: _.get(json, 'request.tests', ''),
docs: _.get(json, 'docs', '')
};
// add meta if it exists
// this is only for folder bru file
// in the future, all of this will be replaced by standard bru lang
if (json?.meta) {
collectionBruJson.meta = {
name: json.meta.name
};
}
if (!isFolder) {
collectionBruJson.auth = _.get(json, 'request.auth', {});
}
return _jsonToCollectionBru(collectionBruJson);
} catch (error) {
return Promise.reject(error);
}
};
const bruToEnvJson = async (bru) => {
try {
const json = bruToEnvJsonV2(bru);
// the app env format requires each variable to have a type
// this need to be evaluated and safely removed
// i don't see it being used in schema validation
if (json && json.variables && json.variables.length) {
_.each(json.variables, (v) => (v.type = 'text'));
}
return json;
} catch (error) {
return Promise.reject(error);
}
};
const envJsonToBru = async (json) => {
try {
const bru = envJsonToBruV2(json);
return bru;
} catch (error) {
return Promise.reject(error);
}
};
/**
* The transformer function for converting a BRU file to JSON.
*
* We map the json response from the bru lang and transform it into the DSL
* format that the app uses
*
* @param {string} data The BRU file content.
* @param {string} bru The BRU file content.
* @returns {object} The JSON representation of the BRU file.
*/
const bruToJson = (data, parsed = false) => {
const parseRequest = async (bru, options = {}) => {
try {
const json = parsed ? data : bruToJsonV2(data);
let json;
if(options.useWorker) {
json = await bruParserWorker?.bruToJson(data);
} else {
json = bruToJsonV2(bru);
}
let requestType = _.get(json, 'meta.type');
if (requestType === 'http') {
@@ -153,15 +68,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);
}
};
/**
* The transformer function for converting a JSON to BRU file.
*
@@ -171,7 +77,7 @@ const bruToJsonViaWorker = async (data) => {
* @param {object} json The JSON representation of the BRU file.
* @returns {string} The BRU file content.
*/
const jsonToBru = async (json) => {
const stringifyRequest = async (json, options = {}) => {
let type = _.get(json, 'type');
if (type === 'http-request') {
type = 'http';
@@ -208,59 +114,140 @@ const jsonToBru = async (json) => {
docs: _.get(json, 'request.docs', '')
};
const bru = jsonToBruV2(bruJson);
return bru;
if(options.useWorker) {
return await bruParserWorker?.jsonToBru(bruJson);
} else {
return jsonToBruV2(bruJson);
}
};
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 parseCollection = async (bru) => {
try {
const json = collectionBruToJson(bru);
const transformedJson = {
request: {
headers: _.get(json, 'headers', []),
auth: _.get(json, 'auth', {}),
script: _.get(json, 'script', {}),
vars: _.get(json, 'vars', {}),
tests: _.get(json, 'tests', '')
},
docs: _.get(json, 'docs', '')
};
return transformedJson;
} catch (error) {
return Promise.reject(error);
}
};
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 stringifyCollection = async (json) => {
try {
const collectionBruJson = {
headers: _.get(json, 'request.headers', []),
auth: _.get(json, 'request.auth', {}),
script: {
req: _.get(json, 'request.script.req', ''),
res: _.get(json, 'request.script.res', '')
},
vars: {
req: _.get(json, 'request.vars.req', []),
res: _.get(json, 'request.vars.res', [])
},
tests: _.get(json, 'request.tests', ''),
docs: _.get(json, 'docs', '')
};
const bru = await bruParserWorker?.jsonToBru(bruJson)
return bru;
return jsonToCollectionBru(collectionBruJson);
} catch (error) {
return Promise.reject(error);
}
};
const parseFolder = async (bru) => {
try {
const json = collectionBruToJson(bru);
const transformedJson = {
meta: {
name: _.get(json, 'meta.name')
},
request: {
headers: _.get(json, 'headers', []),
auth: _.get(json, 'auth', {}),
script: _.get(json, 'script', {}),
vars: _.get(json, 'vars', {}),
tests: _.get(json, 'tests', '')
},
docs: _.get(json, 'docs', '')
};
return transformedJson;
} catch (error) {
return Promise.reject(error);
}
};
const stringifyFolder = async (json) => {
try {
const folderBruJson = {
meta: {
name: _.get(json, 'meta.name')
},
headers: _.get(json, 'request.headers', []),
script: {
req: _.get(json, 'request.script.req', ''),
res: _.get(json, 'request.script.res', '')
},
vars: {
req: _.get(json, 'request.vars.req', []),
res: _.get(json, 'request.vars.res', [])
},
tests: _.get(json, 'request.tests', ''),
docs: _.get(json, 'docs', '')
};
return jsonToCollectionBru(folderBruJson);
} catch (error) {
return Promise.reject(error);
}
};
const parseEnvironment = async (bru) => {
try {
const json = bruToEnvJsonV2(bru);
// the app env format requires each variable to have a type
// this need to be evaluated and safely removed
// i don't see it being used in schema validation
if (json && json.variables && json.variables.length) {
_.each(json.variables, (v) => (v.type = 'text'));
}
return json;
} catch (error) {
return Promise.reject(error);
}
};
const stringifyEnvironment = async (json) => {
try {
const bru = envJsonToBruV2(json);
return bru;
} catch (error) {
return Promise.reject(error);
}
};
module.exports = {
bruToJson,
bruToJsonViaWorker,
jsonToBru,
bruToEnvJson,
envJsonToBru,
collectionBruToJson,
jsonToCollectionBru,
jsonToBruViaWorker
parseRequest,
stringifyRequest,
parseCollection,
stringifyCollection,
parseFolder,
stringifyFolder,
parseEnvironment,
stringifyEnvironment
};

View File

@@ -0,0 +1,69 @@
import {
parseRequest as bruParseRequest,
stringifyRequest as bruStringifyRequest,
parseFolder as bruParseFolder,
stringifyFolder as bruStringifyFolder,
parseCollection as bruParseCollection,
stringifyCollection as bruStringifyCollection,
parseEnvironment as bruParseEnvironment,
stringifyEnvironment as bruStringifyEnvironment
} from './bru';
const parseRequest = (bru, options = {}) => {
if (options.format === 'bru') {
return bruParseRequest(bru);
}
};
const stringifyRequest = (json, options = {}) => {
if (options.format === 'bru') {
return bruStringifyRequest(json);
}
};
const parseFolder = (bru, options = {}) => {
if (options.format === 'bru') {
return bruParseFolder(bru);
}
};
const stringifyFolder = (json, options = {}) => {
if (options.format === 'bru') {
return bruStringifyFolder(json);
}
};
const parseCollection = (bru, options = {}) => {
if (options.format === 'bru') {
return bruParseCollection(bru);
}
};
const stringifyCollection = (json, options = {}) => {
if (options.format === 'bru') {
return bruStringifyCollection(json);
}
};
const parseEnvironment = (bru, options = {}) => {
if (options.format === 'bru') {
return bruParseEnvironment(bru);
}
};
const stringifyEnvironment = (json, options = {}) => {
if (options.format === 'bru') {
return bruStringifyEnvironment(json);
}
};
module.exports = {
parseRequest,
stringifyRequest,
parseFolder,
stringifyFolder,
parseCollection,
stringifyCollection,
parseEnvironment,
stringifyEnvironment
};