Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions test/sorting.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,29 @@ describe('openapi-format CLI sorting tests', () => {
fromEntriesSpy.mockRestore();
});

it('sortPathsByAlphabet - should order a path before its trailing-slash variant regardless of input order', () => {
// A path and its trailing-slash variant differ only by an empty
// segment. The comparator must return the same result no matter which
// order they appear in the input, otherwise they swap between runs.
const expected = ['/pets', '/pets/'];

const sortedA = sortPathsByAlphabet({'/pets/': {get: {}}, '/pets': {get: {}}});
const sortedB = sortPathsByAlphabet({'/pets': {get: {}}, '/pets/': {get: {}}});

expect(Object.keys(sortedA)).toEqual(expected);
expect(Object.keys(sortedB)).toEqual(expected);
});

it('sortPathsByAlphabet - should keep a shorter path before its trailing-slash variant and deeper children', () => {
const sorted = sortPathsByAlphabet({
'/pets/{id}': {get: {}},
'/pets/': {get: {}},
'/pets': {get: {}}
});

expect(Object.keys(sorted)).toEqual(['/pets', '/pets/', '/pets/{id}']);
});

it('pathToRegExp and matchPath - should support named params in strict matching', () => {
const regex = pathToRegExp('/messages/:id');
expect(regex).toBeInstanceOf(RegExp);
Expand Down
11 changes: 9 additions & 2 deletions utils/sorting.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,15 @@ function sortPathsByAlphabet(paths) {
const pathB = b[0].split('/');

for (let i = 1; i < Math.max(pathA.length, pathB.length); i++) {
if (!pathA[i]) return -1;
if (!pathB[i]) return 1;
// Use a strict `undefined` check so a missing segment (the path has
// ended) is treated differently from an empty segment produced by a
// trailing slash. A truthy `!segment` test conflates the two, which
// makes the comparator inconsistent for paths that differ only by a
// trailing slash (e.g. `/pets` vs `/pets/`): both `compare(a, b)` and
// `compare(b, a)` would return -1, so their order depends on the input
// order and flips between runs.
if (pathA[i] === undefined) return -1;
if (pathB[i] === undefined) return 1;
if (pathA[i] < pathB[i]) return -1;
if (pathA[i] > pathB[i]) return 1;
}
Expand Down
Loading