Merge pull request #129 from SebastianMC/127-folder-and-file-with-the-same-basename-sorting
#127 - folder and file with the same (base) name advanced sorting support
This commit is contained in:
commit
ac8cbc0efd
|
@ -35,7 +35,11 @@ export enum CustomSortOrder {
|
|||
standardObsidian, // whatever user selected in the UI
|
||||
byBookmarkOrder,
|
||||
byBookmarkOrderReverse,
|
||||
default = alphabetical
|
||||
fileFirst,
|
||||
folderFirst,
|
||||
alphabeticalWithFilesPreferred, // When the (base)names are equal, the file has precedence over a folder
|
||||
alphabeticalWithFoldersPreferred, // When the (base)names are equal, the file has precedence over a folder
|
||||
default = alphabeticalWithFilesPreferred
|
||||
}
|
||||
|
||||
export interface RecognizedOrderValue {
|
||||
|
|
|
@ -22,6 +22,9 @@ import {
|
|||
sorterByMetadataField,
|
||||
SorterFn
|
||||
} from './custom-sort';
|
||||
import {
|
||||
_unitTests
|
||||
} from './custom-sort'
|
||||
import {
|
||||
CustomSortGroupType,
|
||||
CustomSortOrder,
|
||||
|
@ -2959,3 +2962,38 @@ describe('sorterByFolderCDate', () => {
|
|||
expect(normalizedResultR2).toBe(orderReverseRevParams)
|
||||
})
|
||||
})
|
||||
|
||||
describe('fileGoesFirstWhenSameBasenameAsFolder', () => {
|
||||
const file = 'file'
|
||||
const folder = 'folder'
|
||||
it.each([
|
||||
// main scenario - file goes first unconditionally before folder with the same name
|
||||
[0, file, folder, -1, 1],
|
||||
[0, folder, file, 1, -1],
|
||||
// Not possible - two folders with the same name - the test only documents the behavior for clarity
|
||||
[0, folder, folder, 0, 0],
|
||||
// Realistic yet useless - two files with the same basename,
|
||||
[0, file, file, 0, 0],
|
||||
// Obvious cases - text compare returned !== 0, simply pass through
|
||||
[1, file, file, 1, 1],
|
||||
[1, file, folder, 1, 1],
|
||||
[1, folder, file, 1, 1],
|
||||
[1, folder, folder, 1, 1],
|
||||
[-1, file, file, -1, -1],
|
||||
[-1, file, folder, -1, -1],
|
||||
[-1, folder, file, -1, -1],
|
||||
[-1, folder, folder, -1, -1],
|
||||
])('text compare %s of %s %s gives %s (files first) and %s (folders first)',
|
||||
(textCompare: number, aIsFolder: string, bIsFolder: string, filePreferredOder: number, folderPreferredOrder: number) => {
|
||||
// given
|
||||
const a: Partial<FolderItemForSorting> = { isFolder: aIsFolder === folder }
|
||||
const b: Partial<FolderItemForSorting> = { isFolder: bIsFolder === folder }
|
||||
|
||||
const resultFilePreferred: number = _unitTests.fileGoesFirstWhenSameBasenameAsFolder(textCompare, a as FolderItemForSorting, b as FolderItemForSorting)
|
||||
const resultFolderPreferred: number = _unitTests.folderGoesFirstWhenSameBasenameAsFolder(textCompare, a as FolderItemForSorting, b as FolderItemForSorting)
|
||||
|
||||
// then
|
||||
expect(resultFilePreferred).toBe(filePreferredOder)
|
||||
expect(resultFolderPreferred).toBe(folderPreferredOrder)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -169,8 +169,18 @@ export const sorterByFolderMDate:(reverseOrder?: boolean) => SorterFn = (reverse
|
|||
}
|
||||
}
|
||||
|
||||
type FIFS = FolderItemForSorting
|
||||
|
||||
const fileGoesFirstWhenSameBasenameAsFolder = (stringCompareResult: number, a: FIFS, b: FIFS) =>
|
||||
(!!stringCompareResult) ? stringCompareResult : (a.isFolder === b.isFolder ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? 1 : -1) );
|
||||
|
||||
const folderGoesFirstWhenSameBasenameAsFolder = (stringCompareResult: number, a: FIFS, b: FIFS) =>
|
||||
(!!stringCompareResult) ? stringCompareResult : (a.isFolder === b.isFolder ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? -1 : 1) );
|
||||
|
||||
const Sorters: { [key in CustomSortOrder]: SorterFn } = {
|
||||
[CustomSortOrder.alphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(a.sortString, b.sortString),
|
||||
[CustomSortOrder.alphabeticalWithFilesPreferred]: (a: FIFS, b: FIFS) => fileGoesFirstWhenSameBasenameAsFolder(CollatorCompare(a.sortString, b.sortString),a,b),
|
||||
[CustomSortOrder.alphabeticalWithFoldersPreferred]: (a: FIFS, b: FIFS) => fileGoesFirstWhenSameBasenameAsFolder(CollatorCompare(a.sortString, b.sortString),a,b),
|
||||
[CustomSortOrder.alphabeticalWithFileExt]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(a.sortStringWithExt, b.sortStringWithExt),
|
||||
[CustomSortOrder.trueAlphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabeticalCompare(a.sortString, b.sortString),
|
||||
[CustomSortOrder.trueAlphabeticalWithFileExt]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabeticalCompare(a.sortStringWithExt, b.sortStringWithExt),
|
||||
|
@ -192,9 +202,11 @@ const Sorters: { [key in CustomSortOrder]: SorterFn } = {
|
|||
[CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, TrueAlphabetical, SortingLevelId.forPrimary),
|
||||
[CustomSortOrder.byBookmarkOrder]: sorterByBookmarkOrder(StraightOrder),
|
||||
[CustomSortOrder.byBookmarkOrderReverse]: sorterByBookmarkOrder(ReverseOrder),
|
||||
[CustomSortOrder.fileFirst]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? 1 : -1),
|
||||
[CustomSortOrder.folderFirst]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? EQUAL_OR_UNCOMPARABLE : (a.isFolder ? -1 : 0),
|
||||
|
||||
// This is a fallback entry which should not be used - the getSorterFor() function below should protect against it
|
||||
[CustomSortOrder.standardObsidian]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(a.sortString, b.sortString),
|
||||
// A fallback entry which should not be used - the getSorterFor() function below should protect against it
|
||||
[CustomSortOrder.standardObsidian]: (a: FIFS, b: FIFS) => CollatorCompare(a.sortString, b.sortString),
|
||||
};
|
||||
|
||||
// Some sorters are different when used in primary vs. secondary sorting order
|
||||
|
@ -729,3 +741,8 @@ export const sortFolderItemsForBookmarking = function (folder: TFolder, items: A
|
|||
return folderItems
|
||||
}
|
||||
};
|
||||
|
||||
export const _unitTests = {
|
||||
fileGoesFirstWhenSameBasenameAsFolder: fileGoesFirstWhenSameBasenameAsFolder,
|
||||
folderGoesFirstWhenSameBasenameAsFolder: folderGoesFirstWhenSameBasenameAsFolder
|
||||
}
|
||||
|
|
|
@ -527,6 +527,49 @@ describe('SortingSpecProcessor', () => {
|
|||
})
|
||||
})
|
||||
|
||||
const txtInputFilesOrFoldersPreferred: string = `
|
||||
target-folder: AAA
|
||||
< a-z, files-first
|
||||
subitems1...
|
||||
> folders-first, true a-z.
|
||||
subitems2...
|
||||
< created, folders-first
|
||||
`
|
||||
|
||||
const expectedSortSpecForFilesOrFoldersPreferred: { [key: string]: CustomSortSpec } = {
|
||||
"AAA": {
|
||||
defaultOrder: CustomSortOrder.alphabetical,
|
||||
defaultSecondaryOrder: CustomSortOrder.fileFirst,
|
||||
groups: [{
|
||||
exactPrefix: 'subitems1',
|
||||
order: CustomSortOrder.folderFirst,
|
||||
secondaryOrder: CustomSortOrder.trueAlphabeticalWithFileExt,
|
||||
type: CustomSortGroupType.ExactPrefix
|
||||
},{
|
||||
exactPrefix: 'subitems2',
|
||||
order: CustomSortOrder.byCreatedTime,
|
||||
secondaryOrder: CustomSortOrder.folderFirst,
|
||||
type: CustomSortGroupType.ExactPrefix
|
||||
}, {
|
||||
type: CustomSortGroupType.Outsiders
|
||||
}],
|
||||
outsidersGroupIdx: 2,
|
||||
targetFoldersPaths: ['AAA']
|
||||
}
|
||||
}
|
||||
|
||||
describe('SortingSpecProcessor', () => {
|
||||
let processor: SortingSpecProcessor;
|
||||
beforeEach(() => {
|
||||
processor = new SortingSpecProcessor();
|
||||
});
|
||||
it('should recognize the files / folders preferred as a primary and secondary orders', () => {
|
||||
const inputTxtArr: Array<string> = txtInputFilesOrFoldersPreferred.split('\n')
|
||||
const result = processor.parseSortSpecFromText(inputTxtArr, 'mock-folder', 'custom-name-note.md')
|
||||
expect(result?.sortSpecByPath).toEqual(expectedSortSpecForFilesOrFoldersPreferred)
|
||||
})
|
||||
})
|
||||
|
||||
const txtInputThreeDotsCases: string = `
|
||||
target-folder: AAA
|
||||
...
|
||||
|
|
|
@ -127,6 +127,8 @@ const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = {
|
|||
'standard': {asc: CustomSortOrder.standardObsidian, desc: CustomSortOrder.standardObsidian},
|
||||
'ui selected': {asc: CustomSortOrder.standardObsidian, desc: CustomSortOrder.standardObsidian},
|
||||
'by-bookmarks-order': {asc: CustomSortOrder.byBookmarkOrder, desc: CustomSortOrder.byBookmarkOrderReverse},
|
||||
'files-first': {asc: CustomSortOrder.fileFirst, desc: CustomSortOrder.fileFirst},
|
||||
'folders-first': {asc: CustomSortOrder.folderFirst, desc: CustomSortOrder.folderFirst}
|
||||
}
|
||||
|
||||
const OrderByMetadataLexeme: string = 'by-metadata:'
|
||||
|
|
Loading…
Reference in New Issue