Skip to content

Commit a07cb28

Browse files
feat: implement item sorting for Postman export
- Added functions to sort items by sequence and name, ensuring folders are prioritized over requests in the export output. - Enhanced the `brunoToPostman` function to utilize the new sorting logic. - Introduced comprehensive tests to validate the sorting behavior for folders and requests, including nested structures.
1 parent 9944819 commit a07cb28

2 files changed

Lines changed: 158 additions & 1 deletion

File tree

packages/bruno-converters/src/postman/bruno-to-postman.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,51 @@ import map from 'lodash/map';
22
import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems, isItemARequest } from '../common';
33
import translateBruToPostman from '../utils/bruno-to-postman-translator';
44

5+
const isItemAFolder = (item) => item.type === 'folder';
6+
7+
const sortItemsBySequence = (items) => [...items].sort((a, b) => a.seq - b.seq);
8+
9+
const sortByNameThenSequence = (items) => {
10+
const isSeqValid = (seq) => Number.isFinite(seq) && Number.isInteger(seq) && seq > 0;
11+
12+
const alphabeticallySorted = [...items].sort((a, b) => a.name && b.name && a.name.localeCompare(b.name));
13+
14+
const withoutSeq = alphabeticallySorted.filter((f) => !isSeqValid(f['seq']));
15+
const withSeq = alphabeticallySorted.filter((f) => isSeqValid(f['seq'])).sort((a, b) => a.seq - b.seq);
16+
17+
const sortedItems = withoutSeq;
18+
19+
withSeq.forEach((item) => {
20+
const position = item.seq - 1;
21+
const existingItem = withoutSeq[position];
22+
23+
const hasItemWithSameSeq = Array.isArray(existingItem)
24+
? existingItem?.[0]?.seq === item.seq
25+
: existingItem?.seq === item.seq;
26+
27+
if (hasItemWithSameSeq) {
28+
const newGroup = Array.isArray(existingItem) ? [...existingItem, item] : [existingItem, item];
29+
withoutSeq.splice(position, 1, newGroup);
30+
} else {
31+
withoutSeq.splice(position, 0, item);
32+
}
33+
});
34+
35+
return sortedItems.flat();
36+
};
37+
38+
const sortItemsForExport = (items) => {
39+
if (!items || !Array.isArray(items)) return [];
40+
41+
const folders = items.filter((item) => item && isItemAFolder(item));
42+
const requests = items.filter((item) => item && isItemARequest(item));
43+
44+
const sortedFolders = sortByNameThenSequence(folders);
45+
const sortedRequests = sortItemsBySequence(requests);
46+
47+
return [...sortedFolders, ...sortedRequests];
48+
};
49+
550
/**
651
* Transforms a given URL string into an object representing the protocol, host, path, query, and variables.
752
*
@@ -497,7 +542,9 @@ export const brunoToPostman = (collection) => {
497542
return [];
498543
}
499544

500-
return map(itemsArray, (item) => {
545+
const sortedItems = sortItemsForExport(itemsArray);
546+
547+
return map(sortedItems, (item) => {
501548
if (!item) {
502549
return null;
503550
}

packages/bruno-converters/tests/postman/bruno-to-postman.spec.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,3 +937,113 @@ describe('brunoToPostman event handling', () => {
937937
expect(nestedRequest.event[0].script.exec).toEqual(['console.log("nested pre");']);
938938
});
939939
});
940+
941+
describe('brunoToPostman item ordering', () => {
942+
const makeRequest = (name, seq) => ({
943+
type: 'http-request',
944+
name,
945+
seq,
946+
request: {
947+
method: 'GET',
948+
url: 'https://example.com',
949+
headers: [],
950+
params: [],
951+
body: { mode: 'none' },
952+
auth: { mode: 'none' }
953+
}
954+
});
955+
956+
const makeFolder = (name, seq, items = []) => ({
957+
type: 'folder',
958+
name,
959+
seq,
960+
items
961+
});
962+
963+
it('should place folders before requests in export output', () => {
964+
const collection = {
965+
items: [
966+
makeRequest('Request A', 1),
967+
makeFolder('Folder B'),
968+
makeRequest('Request C', 2),
969+
makeFolder('Folder A')
970+
]
971+
};
972+
973+
const result = brunoToPostman(collection);
974+
const names = result.item.map((i) => i.name);
975+
976+
// Folders first (alphabetical since no seq), then requests (by seq)
977+
expect(names[0]).toBe('Folder A');
978+
expect(names[1]).toBe('Folder B');
979+
expect(names[2]).toBe('Request A');
980+
expect(names[3]).toBe('Request C');
981+
});
982+
983+
it('should sort requests by seq ascending', () => {
984+
const collection = {
985+
items: [
986+
makeRequest('Third', 3),
987+
makeRequest('First', 1),
988+
makeRequest('Second', 2)
989+
]
990+
};
991+
992+
const result = brunoToPostman(collection);
993+
const names = result.item.map((i) => i.name);
994+
995+
expect(names).toEqual(['First', 'Second', 'Third']);
996+
});
997+
998+
it('should sort folders by name then sequence', () => {
999+
const collection = {
1000+
items: [
1001+
makeFolder('Gamma', undefined),
1002+
makeFolder('Alpha', undefined),
1003+
makeFolder('Beta', 1)
1004+
]
1005+
};
1006+
1007+
const result = brunoToPostman(collection);
1008+
const names = result.item.map((i) => i.name);
1009+
1010+
// Beta has seq=1, so it goes to position 0; Alpha and Gamma are alphabetical
1011+
expect(names[0]).toBe('Beta');
1012+
expect(names[1]).toBe('Alpha');
1013+
expect(names[2]).toBe('Gamma');
1014+
});
1015+
1016+
it('should sort items recursively within nested folders', () => {
1017+
const collection = {
1018+
items: [
1019+
makeFolder('Parent', 1, [
1020+
makeRequest('Nested C', 3),
1021+
makeFolder('Nested Folder', 1),
1022+
makeRequest('Nested A', 1)
1023+
])
1024+
]
1025+
};
1026+
1027+
const result = brunoToPostman(collection);
1028+
const parent = result.item[0];
1029+
const nestedNames = parent.item.map((i) => i.name);
1030+
1031+
// Folder first, then requests sorted by seq
1032+
expect(nestedNames).toEqual(['Nested Folder', 'Nested A', 'Nested C']);
1033+
});
1034+
1035+
it('should handle folders without seq (older collections) alphabetically', () => {
1036+
const collection = {
1037+
items: [
1038+
makeFolder('Zebra', undefined),
1039+
makeFolder('Apple', undefined),
1040+
makeFolder('Mango', undefined)
1041+
]
1042+
};
1043+
1044+
const result = brunoToPostman(collection);
1045+
const names = result.item.map((i) => i.name);
1046+
1047+
expect(names).toEqual(['Apple', 'Mango', 'Zebra']);
1048+
});
1049+
});

0 commit comments

Comments
 (0)