Merge branch 'master' into 74-integration-with-bookmarks-core-plugin
# Conflicts: # src/custom-sort/custom-sort.spec.ts # src/custom-sort/custom-sort.ts
This commit is contained in:
commit
527a03b050
|
@ -0,0 +1,294 @@
|
||||||
|
import {
|
||||||
|
FolderItemForSorting,
|
||||||
|
getComparator,
|
||||||
|
getSorterFnFor,
|
||||||
|
getMdata,
|
||||||
|
OS_byCreatedTime,
|
||||||
|
OS_byModifiedTime,
|
||||||
|
OS_byModifiedTimeReverse, SortingLevelId
|
||||||
|
} from './custom-sort';
|
||||||
|
import * as CustomSortModule from './custom-sort';
|
||||||
|
import {CustomSortGroupType, CustomSortOrder, CustomSortSpec} from './custom-sort-types';
|
||||||
|
|
||||||
|
const MOCK_TIMESTAMP: number = 1656417542418
|
||||||
|
|
||||||
|
const FlatLevelSortSpec: CustomSortSpec = {
|
||||||
|
groups: [{ // Not relevant in unit test
|
||||||
|
exactText: "Nothing",
|
||||||
|
filesOnly: true,
|
||||||
|
order: CustomSortOrder.alphabetical,
|
||||||
|
type: CustomSortGroupType.ExactName
|
||||||
|
},{ // prepared for unit test
|
||||||
|
exactPrefix: "Fi",
|
||||||
|
order: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
||||||
|
type: CustomSortGroupType.ExactPrefix
|
||||||
|
},{ // Not relevant in unit test
|
||||||
|
type: CustomSortGroupType.Outsiders,
|
||||||
|
order: CustomSortOrder.byCreatedTime
|
||||||
|
}],
|
||||||
|
outsidersGroupIdx: 2,
|
||||||
|
defaultOrder: CustomSortOrder.byCreatedTime,
|
||||||
|
targetFoldersPaths: ['parent folder']
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultiLevelSortSpecGroupLevel: CustomSortSpec = {
|
||||||
|
groups: [{ // Not relevant in unit test
|
||||||
|
exactText: "Nothing",
|
||||||
|
filesOnly: true,
|
||||||
|
order: CustomSortOrder.alphabetical,
|
||||||
|
type: CustomSortGroupType.ExactName
|
||||||
|
},{ // prepared for unit test
|
||||||
|
exactPrefix: "Fi",
|
||||||
|
order: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
||||||
|
type: CustomSortGroupType.ExactPrefix
|
||||||
|
},{ // Not relevant in unit test
|
||||||
|
type: CustomSortGroupType.Outsiders,
|
||||||
|
order: CustomSortOrder.byCreatedTime
|
||||||
|
}],
|
||||||
|
outsidersGroupIdx: 2,
|
||||||
|
defaultOrder: CustomSortOrder.byCreatedTime,
|
||||||
|
targetFoldersPaths: ['parent folder']
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultiLevelSortSpecTargetFolderLevel: CustomSortSpec = {
|
||||||
|
groups: [{ // Not relevant in unit test
|
||||||
|
exactText: "Nothing",
|
||||||
|
filesOnly: true,
|
||||||
|
order: CustomSortOrder.alphabetical,
|
||||||
|
type: CustomSortGroupType.ExactName
|
||||||
|
},{ // prepared for unit test
|
||||||
|
exactPrefix: "Fi",
|
||||||
|
order: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
||||||
|
type: CustomSortGroupType.ExactPrefix
|
||||||
|
},{ // Not relevant in unit test
|
||||||
|
type: CustomSortGroupType.Outsiders,
|
||||||
|
order: CustomSortOrder.byCreatedTime
|
||||||
|
}],
|
||||||
|
outsidersGroupIdx: 2,
|
||||||
|
defaultOrder: CustomSortOrder.byCreatedTime,
|
||||||
|
defaultSecondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse,
|
||||||
|
targetFoldersPaths: ['parent folder']
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultiLevelSortSpecAndTargetFolderLevel: CustomSortSpec = {
|
||||||
|
groups: [{ // Not relevant in unit test
|
||||||
|
exactText: "Nothing",
|
||||||
|
filesOnly: true,
|
||||||
|
order: CustomSortOrder.alphabetical,
|
||||||
|
type: CustomSortGroupType.ExactName
|
||||||
|
},{ // prepared for unit test
|
||||||
|
exactPrefix: "Fi",
|
||||||
|
order: CustomSortOrder.byMetadataFieldAlphabetical,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
||||||
|
type: CustomSortGroupType.ExactPrefix
|
||||||
|
},{ // Not relevant in unit test
|
||||||
|
type: CustomSortGroupType.Outsiders,
|
||||||
|
order: CustomSortOrder.byCreatedTime
|
||||||
|
}],
|
||||||
|
outsidersGroupIdx: 2,
|
||||||
|
defaultOrder: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
||||||
|
defaultSecondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse,
|
||||||
|
targetFoldersPaths: ['parent folder']
|
||||||
|
}
|
||||||
|
|
||||||
|
const A_GOES_FIRST: number = -1
|
||||||
|
const B_GOES_FIRST: number = 1
|
||||||
|
const AB_EQUAL: number = 0
|
||||||
|
|
||||||
|
const BaseItemForSorting1: FolderItemForSorting = {
|
||||||
|
groupIdx: 1,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'parent folder/References.md',
|
||||||
|
metadataFieldValue: 'direct metadata on file, under default name',
|
||||||
|
metadataFieldValueSecondary: 'only used if secondary sort by metadata is used',
|
||||||
|
metadataFieldValueForDerived: 'only used if derived primary sort by metadata is used',
|
||||||
|
metadataFieldValueForDerivedSecondary: 'only used if derived secondary sort by metadata is used'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBaseItemForSorting(overrides?: Partial<FolderItemForSorting>): FolderItemForSorting {
|
||||||
|
return Object.assign({}, BaseItemForSorting1, overrides)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getComparator', () => {
|
||||||
|
const sp = jest.spyOn(CustomSortModule, 'getSorterFnFor')
|
||||||
|
const collatorCmp = jest.spyOn(CustomSortModule, 'CollatorCompare')
|
||||||
|
beforeEach(() => {
|
||||||
|
sp.mockClear()
|
||||||
|
})
|
||||||
|
describe('should correctly handle flat sorting spec', () => {
|
||||||
|
const comparator = getComparator(FlatLevelSortSpec, OS_byModifiedTime)
|
||||||
|
it( 'in simple case - group-level comparison succeeds', () => {
|
||||||
|
const a = getBaseItemForSorting({
|
||||||
|
metadataFieldValue: 'value X'
|
||||||
|
})
|
||||||
|
const b= getBaseItemForSorting({
|
||||||
|
metadataFieldValue: 'value Y'
|
||||||
|
})
|
||||||
|
const result = comparator(a,b)
|
||||||
|
expect(result).toBe(B_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(1)
|
||||||
|
expect(sp).toBeCalledWith(CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTime, SortingLevelId.forPrimary)
|
||||||
|
})
|
||||||
|
it( 'in simple case - group-level comparison fails, use folder-level', () => {
|
||||||
|
const a = getBaseItemForSorting()
|
||||||
|
const b= getBaseItemForSorting({
|
||||||
|
ctime: a.ctime - 100
|
||||||
|
})
|
||||||
|
const result = Math.sign(comparator(a,b))
|
||||||
|
expect(result).toBe(B_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(2)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTime, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byCreatedTime, OS_byModifiedTime, SortingLevelId.forDerivedPrimary)
|
||||||
|
})
|
||||||
|
it( 'in simple case - group-level comparison fails, folder-level fails, ui-selected in effect', () => {
|
||||||
|
const a = getBaseItemForSorting()
|
||||||
|
const b= getBaseItemForSorting({
|
||||||
|
mtime: a.mtime + 100 // Make be fresher than a
|
||||||
|
})
|
||||||
|
const result = Math.sign(comparator(a,b))
|
||||||
|
expect(result).toBe(B_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(3)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTime, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byCreatedTime, OS_byModifiedTime, SortingLevelId.forDerivedPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(3, CustomSortOrder.standardObsidian, OS_byModifiedTime, SortingLevelId.forUISelected)
|
||||||
|
})
|
||||||
|
it( 'in simple case - group-level comparison fails, folder-level fails, ui-selected fails, the last resort default comes into play - case A', () => {
|
||||||
|
const a = getBaseItemForSorting({
|
||||||
|
sortString: 'Second'
|
||||||
|
})
|
||||||
|
const b= getBaseItemForSorting({
|
||||||
|
sortString: 'First'
|
||||||
|
})
|
||||||
|
const result = comparator(a,b)
|
||||||
|
expect(result).toBe(B_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(4)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTime, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byCreatedTime, OS_byModifiedTime, SortingLevelId.forDerivedPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(3, CustomSortOrder.standardObsidian, OS_byModifiedTime, SortingLevelId.forUISelected)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(4, CustomSortOrder.default, undefined, SortingLevelId.forLastResort)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('should correctly handle secondary sorting spec', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
sp.mockClear()
|
||||||
|
})
|
||||||
|
describe('at group level', () => {
|
||||||
|
const comparator = getComparator(MultiLevelSortSpecGroupLevel, OS_byModifiedTimeReverse)
|
||||||
|
it('in simple case - secondary sort comparison succeeds', () => {
|
||||||
|
const a = getBaseItemForSorting({
|
||||||
|
metadataFieldValueSecondary: 'This goes 1'
|
||||||
|
})
|
||||||
|
const b = getBaseItemForSorting({
|
||||||
|
metadataFieldValueSecondary: 'This goes 2'
|
||||||
|
})
|
||||||
|
const result = comparator(a, b)
|
||||||
|
expect(result).toBe(A_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(2)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTimeReverse, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byMetadataFieldTrueAlphabetical, OS_byModifiedTimeReverse, SortingLevelId.forSecondary)
|
||||||
|
})
|
||||||
|
it( 'in complex case - secondary sort comparison fails, last resort comes into play', () => {
|
||||||
|
const a = getBaseItemForSorting({
|
||||||
|
sortString: 'Second'
|
||||||
|
})
|
||||||
|
const b= getBaseItemForSorting({
|
||||||
|
sortString: 'First'
|
||||||
|
})
|
||||||
|
const result = comparator(a,b)
|
||||||
|
expect(result).toBe(B_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(5)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTimeReverse, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byMetadataFieldTrueAlphabetical, OS_byModifiedTimeReverse, SortingLevelId.forSecondary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(3, CustomSortOrder.byCreatedTime, OS_byModifiedTimeReverse, SortingLevelId.forDerivedPrimary )
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(4, CustomSortOrder.standardObsidian, OS_byModifiedTimeReverse, SortingLevelId.forUISelected)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(5, CustomSortOrder.default, undefined, SortingLevelId.forLastResort)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('at target folder level (aka derived)', () => {
|
||||||
|
const comparator = getComparator(MultiLevelSortSpecTargetFolderLevel, OS_byModifiedTimeReverse)
|
||||||
|
it('in simple case - derived secondary sort comparison succeeds', () => {
|
||||||
|
const a = getBaseItemForSorting({
|
||||||
|
metadataFieldValueForDerivedSecondary: 'This goes 2 first (reverse is in effect)'
|
||||||
|
})
|
||||||
|
const b = getBaseItemForSorting({
|
||||||
|
metadataFieldValueForDerivedSecondary: 'This goes 1 second (reverse is in effect)'
|
||||||
|
})
|
||||||
|
const result = comparator(a, b)
|
||||||
|
expect(result).toBe(A_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(3)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTimeReverse, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byCreatedTime, OS_byModifiedTimeReverse, SortingLevelId.forDerivedPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(3, CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse, OS_byModifiedTimeReverse, SortingLevelId.forDerivedSecondary)
|
||||||
|
})
|
||||||
|
it( 'in complex case - secondary sort comparison fails, last resort comes into play', () => {
|
||||||
|
const a = getBaseItemForSorting({
|
||||||
|
sortString: 'Second'
|
||||||
|
})
|
||||||
|
const b= getBaseItemForSorting({
|
||||||
|
sortString: 'First'
|
||||||
|
})
|
||||||
|
const result = comparator(a,b)
|
||||||
|
expect(result).toBe(B_GOES_FIRST)
|
||||||
|
expect(sp).toBeCalledTimes(5)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byModifiedTimeReverse, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byCreatedTime, OS_byModifiedTimeReverse, SortingLevelId.forDerivedPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(3, CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse, OS_byModifiedTimeReverse, SortingLevelId.forDerivedSecondary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(4, CustomSortOrder.standardObsidian, OS_byModifiedTimeReverse, SortingLevelId.forUISelected)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(5, CustomSortOrder.default, undefined, SortingLevelId.forLastResort)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('at group and at target folder level (aka derived)', () => {
|
||||||
|
const comparator = getComparator(MultiLevelSortSpecAndTargetFolderLevel, OS_byCreatedTime)
|
||||||
|
const mdataGetter = jest.spyOn(CustomSortModule, 'getMdata')
|
||||||
|
beforeEach(() => {
|
||||||
|
mdataGetter.mockClear()
|
||||||
|
})
|
||||||
|
it('most complex case - last resort comest into play, all sort levels present, all involve metadata', () => {
|
||||||
|
const a = getBaseItemForSorting({
|
||||||
|
path: 'test 1', // Not used in comparisons, used only to identify source of compared metadata
|
||||||
|
metadataFieldValue: 'm',
|
||||||
|
metadataFieldValueSecondary: 'ms',
|
||||||
|
metadataFieldValueForDerived: 'dm',
|
||||||
|
metadataFieldValueForDerivedSecondary: 'dms'
|
||||||
|
})
|
||||||
|
const b= getBaseItemForSorting({
|
||||||
|
path: 'test 2', // Not used in comparisons, used only to identify source of compared metadata
|
||||||
|
metadataFieldValue: 'm',
|
||||||
|
metadataFieldValueSecondary: 'ms',
|
||||||
|
metadataFieldValueForDerived: 'dm',
|
||||||
|
metadataFieldValueForDerivedSecondary: 'dms'
|
||||||
|
})
|
||||||
|
const result = Math.sign(comparator(a,b))
|
||||||
|
expect(result).toBe(AB_EQUAL)
|
||||||
|
expect(sp).toBeCalledTimes(6)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(1, CustomSortOrder.byMetadataFieldAlphabetical, OS_byCreatedTime, SortingLevelId.forPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(2, CustomSortOrder.byMetadataFieldAlphabeticalReverse, OS_byCreatedTime, SortingLevelId.forSecondary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(3, CustomSortOrder.byMetadataFieldTrueAlphabetical, OS_byCreatedTime, SortingLevelId.forDerivedPrimary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(4, CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse, OS_byCreatedTime, SortingLevelId.forDerivedSecondary)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(5, CustomSortOrder.standardObsidian, OS_byCreatedTime, SortingLevelId.forUISelected)
|
||||||
|
expect(sp).toHaveBeenNthCalledWith(6, CustomSortOrder.default, undefined, SortingLevelId.forLastResort)
|
||||||
|
expect(mdataGetter).toHaveBeenCalledTimes(8)
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(1, expect.objectContaining({path: 'test 1'}), SortingLevelId.forPrimary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(1, 'm')
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(2, expect.objectContaining({path: 'test 2'}), SortingLevelId.forPrimary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(2, 'm')
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(3, expect.objectContaining({path: 'test 1'}), SortingLevelId.forSecondary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(3, 'ms')
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(4, expect.objectContaining({path: 'test 2'}), SortingLevelId.forSecondary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(4, 'ms')
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(5, expect.objectContaining({path: 'test 1'}), SortingLevelId.forDerivedPrimary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(5, 'dm')
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(6, expect.objectContaining({path: 'test 2'}), SortingLevelId.forDerivedPrimary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(6, 'dm')
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(7, expect.objectContaining({path: 'test 1'}), SortingLevelId.forDerivedSecondary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(7, 'dms')
|
||||||
|
expect(mdataGetter).toHaveBeenNthCalledWith(8, expect.objectContaining({path: 'test 2'}), SortingLevelId.forDerivedSecondary)
|
||||||
|
expect(mdataGetter).toHaveNthReturnedWith(8, 'dms')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -58,6 +58,7 @@ export interface CustomSortGroup {
|
||||||
overrideTitle?: boolean // instead of title, use a derived text for sorting (e.g. regexp matching group).
|
overrideTitle?: boolean // instead of title, use a derived text for sorting (e.g. regexp matching group).
|
||||||
order?: CustomSortOrder
|
order?: CustomSortOrder
|
||||||
byMetadataField?: string // for 'by-metadata:' sorting if the order is by metadata alphabetical or reverse
|
byMetadataField?: string // for 'by-metadata:' sorting if the order is by metadata alphabetical or reverse
|
||||||
|
byMetadataFieldSecondary?: string // for 'by-metadata:' sorting if the order is by metadata alphabetical or reverse
|
||||||
secondaryOrder?: CustomSortOrder
|
secondaryOrder?: CustomSortOrder
|
||||||
filesOnly?: boolean
|
filesOnly?: boolean
|
||||||
matchFilenameWithExt?: boolean
|
matchFilenameWithExt?: boolean
|
||||||
|
@ -72,7 +73,9 @@ export interface CustomSortSpec {
|
||||||
// plays only informative role about the original parsed 'target-folder:' values
|
// plays only informative role about the original parsed 'target-folder:' values
|
||||||
targetFoldersPaths: Array<string> // For root use '/'
|
targetFoldersPaths: Array<string> // For root use '/'
|
||||||
defaultOrder?: CustomSortOrder
|
defaultOrder?: CustomSortOrder
|
||||||
byMetadataField?: string // for 'by-metadata:' if the defaultOrder is by metadata alphabetical or reverse
|
defaultSecondaryOrder?: CustomSortOrder
|
||||||
|
byMetadataField?: string // for 'by-metadata:' if the defaultOrder is by metadata
|
||||||
|
byMetadataFieldSecondary?: string
|
||||||
groups: Array<CustomSortGroup>
|
groups: Array<CustomSortGroup>
|
||||||
groupsShadow?: Array<CustomSortGroup> // A shallow copy of groups, used at applying sorting for items in a folder.
|
groupsShadow?: Array<CustomSortGroup> // A shallow copy of groups, used at applying sorting for items in a folder.
|
||||||
// Stores folder-specific values (e.g. macros expanded with folder-specific values)
|
// Stores folder-specific values (e.g. macros expanded with folder-specific values)
|
||||||
|
|
|
@ -6,12 +6,12 @@ import {
|
||||||
determineSortingGroup,
|
determineSortingGroup,
|
||||||
EQUAL_OR_UNCOMPARABLE,
|
EQUAL_OR_UNCOMPARABLE,
|
||||||
FolderItemForSorting,
|
FolderItemForSorting,
|
||||||
|
getSorterFnFor,
|
||||||
matchGroupRegex,
|
matchGroupRegex,
|
||||||
|
ProcessingContext,
|
||||||
sorterByBookmarkOrder,
|
sorterByBookmarkOrder,
|
||||||
sorterByMetadataField,
|
sorterByMetadataField,
|
||||||
SorterFn,
|
SorterFn
|
||||||
getSorterFnFor,
|
|
||||||
ProcessingContext
|
|
||||||
} from './custom-sort';
|
} from './custom-sort';
|
||||||
import {CustomSortGroupType, CustomSortOrder, CustomSortSpec, RegExpSpec} from './custom-sort-types';
|
import {CustomSortGroupType, CustomSortOrder, CustomSortSpec, RegExpSpec} from './custom-sort-types';
|
||||||
import {CompoundDashNumberNormalizerFn, CompoundDotRomanNumberNormalizerFn} from "./sorting-spec-processor";
|
import {CompoundDashNumberNormalizerFn, CompoundDotRomanNumberNormalizerFn} from "./sorting-spec-processor";
|
||||||
|
@ -1882,7 +1882,7 @@ describe('determineSortingGroup', () => {
|
||||||
ctime: MOCK_TIMESTAMP + 222,
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
mtime: MOCK_TIMESTAMP + 333,
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
path: 'Some parent folder/References.md',
|
path: 'Some parent folder/References.md',
|
||||||
metadataFieldValue: 'direct metadata on file, not obvious'
|
metadataFieldValueForDerived: 'direct metadata on file, not obvious'
|
||||||
} as FolderItemForSorting);
|
} as FolderItemForSorting);
|
||||||
})
|
})
|
||||||
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified on group)', () => {
|
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified on group)', () => {
|
||||||
|
@ -1967,6 +1967,406 @@ describe('determineSortingGroup', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when sort by metadata is involved (specified in secondary sort, for group of for target folder)', () => {
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set on group) alph', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
order: CustomSortOrder.alphabetical,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
"metadata-field-for-sorting": "direct metadata on file",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValueSecondary: 'direct metadata on file'
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set on group) alph rev', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
order: CustomSortOrder.alphabeticalReverse,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
"metadata-field-for-sorting": "direct metadata on file",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValueSecondary: 'direct metadata on file'
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set on group) true alph', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
byMetadataField: 'non-existing-mdata',
|
||||||
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
order: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabetical
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
"metadata-field-for-sorting": "direct metadata on file",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValueSecondary: 'direct metadata on file'
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set on group) true alph rev (dbl mdata)', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
byMetadataField: 'metadata-field-for-sorting',
|
||||||
|
byMetadataFieldSecondary: 'metadata-field-for-sorting secondary',
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
order: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
"metadata-field-for-sorting": "direct metadata on file",
|
||||||
|
"metadata-field-for-sorting secondary": "direct another metadata on file",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValue: 'direct metadata on file',
|
||||||
|
metadataFieldValueSecondary: 'direct another metadata on file'
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
it('should correctly read direct metadata from folder note item (order by metadata set on group)', () => {
|
||||||
|
// given
|
||||||
|
const folder: TFolder = mockTFolder('References');
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
byMetadataFieldSecondary: 'metadata-field-for-sorting',
|
||||||
|
order: CustomSortOrder.standardObsidian,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'References/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
'metadata-field-for-sorting': "metadata on folder note",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(folder, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: true,
|
||||||
|
sortString: "References",
|
||||||
|
ctime: DEFAULT_FOLDER_CTIME,
|
||||||
|
mtime: DEFAULT_FOLDER_MTIME,
|
||||||
|
path: 'References',
|
||||||
|
metadataFieldValueSecondary: 'metadata on folder note',
|
||||||
|
folder: folder
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set on target folder)', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
order: CustomSortOrder.trueAlphabetical,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical
|
||||||
|
}],
|
||||||
|
defaultOrder: CustomSortOrder.byCreatedTime,
|
||||||
|
defaultSecondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
||||||
|
byMetadataFieldSecondary: 'metadata-field-for-sorting-specified-on-target-folder'
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
"metadata-field-for-sorting-specified-on-target-folder": "direct metadata on file, not obvious",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValueForDerivedSecondary: 'direct metadata on file, not obvious'
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified on group)', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.HasMetadataField,
|
||||||
|
order: CustomSortOrder.standardObsidian,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical,
|
||||||
|
withMetadataFieldName: 'field-used-with-with-metadata-syntax'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
'field-used-with-with-metadata-syntax': "direct metadata on file, tricky",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValueSecondary: 'direct metadata on file, tricky',
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set on group, no metadata name specified anywhere)', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
order: CustomSortOrder.byCreatedTimeReverse,
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabetical
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
'sort-index-value': "direct metadata on file, under default name",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValueSecondary: 'direct metadata on file, under default name',
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when sort by metadata is involved, at every level', () => {
|
||||||
|
it('should correctly read direct metadata from File item (order by metadata set at each level)', () => {
|
||||||
|
// given
|
||||||
|
const file: TFile = mockTFile('References', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
const sortSpec: CustomSortSpec = {
|
||||||
|
targetFoldersPaths: ['/'],
|
||||||
|
groups: [{
|
||||||
|
type: CustomSortGroupType.ExactPrefix,
|
||||||
|
exactPrefix: 'Ref',
|
||||||
|
order: CustomSortOrder.byMetadataFieldAlphabetical,
|
||||||
|
byMetadataField: 'mdata-for-primary',
|
||||||
|
secondaryOrder: CustomSortOrder.byMetadataFieldAlphabeticalReverse,
|
||||||
|
byMetadataFieldSecondary: 'mdata-for-secondary'
|
||||||
|
}],
|
||||||
|
defaultOrder: CustomSortOrder.byMetadataFieldTrueAlphabetical,
|
||||||
|
byMetadataField: 'mdata-for-default-primary',
|
||||||
|
defaultSecondaryOrder: CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse,
|
||||||
|
byMetadataFieldSecondary: 'mdata-for-default-secondary'
|
||||||
|
}
|
||||||
|
const ctx: Partial<ProcessingContext> = {
|
||||||
|
_mCache: {
|
||||||
|
getCache: function (path: string): CachedMetadata | undefined {
|
||||||
|
return {
|
||||||
|
'Some parent folder/References.md': {
|
||||||
|
frontmatter: {
|
||||||
|
'mdata-for-primary': "filemdata 1",
|
||||||
|
'mdata-for-secondary': "filemdata 2",
|
||||||
|
'mdata-for-default-primary': "filemdata 3",
|
||||||
|
'mdata-for-default-secondary': "filemdata 4",
|
||||||
|
position: MockedLoc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}[path]
|
||||||
|
}
|
||||||
|
} as MetadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
const result = determineSortingGroup(file, sortSpec, ctx as ProcessingContext)
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(result).toEqual({
|
||||||
|
groupIdx: 0,
|
||||||
|
isFolder: false,
|
||||||
|
sortString: "References.md",
|
||||||
|
ctime: MOCK_TIMESTAMP + 222,
|
||||||
|
mtime: MOCK_TIMESTAMP + 333,
|
||||||
|
path: 'Some parent folder/References.md',
|
||||||
|
metadataFieldValue: 'filemdata 1',
|
||||||
|
metadataFieldValueSecondary: 'filemdata 2',
|
||||||
|
metadataFieldValueForDerived: 'filemdata 3',
|
||||||
|
metadataFieldValueForDerivedSecondary: 'filemdata 4',
|
||||||
|
} as FolderItemForSorting);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should correctly apply priority group', () => {
|
it('should correctly apply priority group', () => {
|
||||||
// given
|
// given
|
||||||
const file: TFile = mockTFile('Abcdef!', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
const file: TFile = mockTFile('Abcdef!', 'md', 111, MOCK_TIMESTAMP + 222, MOCK_TIMESTAMP + 333);
|
||||||
|
|
|
@ -43,13 +43,13 @@ export interface ProcessingContext {
|
||||||
iconFolderPluginInstance?: ObsidianIconFolder_PluginInstance
|
iconFolderPluginInstance?: ObsidianIconFolder_PluginInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
let CollatorCompare = new Intl.Collator(undefined, {
|
export const CollatorCompare = new Intl.Collator(undefined, {
|
||||||
usage: "sort",
|
usage: "sort",
|
||||||
sensitivity: "base",
|
sensitivity: "base",
|
||||||
numeric: true,
|
numeric: true,
|
||||||
}).compare;
|
}).compare;
|
||||||
|
|
||||||
let CollatorTrueAlphabeticalCompare = new Intl.Collator(undefined, {
|
export const CollatorTrueAlphabeticalCompare = new Intl.Collator(undefined, {
|
||||||
usage: "sort",
|
usage: "sort",
|
||||||
sensitivity: "base",
|
sensitivity: "base",
|
||||||
numeric: false,
|
numeric: false,
|
||||||
|
@ -59,7 +59,10 @@ export interface FolderItemForSorting {
|
||||||
path: string
|
path: string
|
||||||
groupIdx?: number // the index itself represents order for groups
|
groupIdx?: number // the index itself represents order for groups
|
||||||
sortString: string // fragment (or full name) to be used for sorting
|
sortString: string // fragment (or full name) to be used for sorting
|
||||||
metadataFieldValue?: string // relevant to metadata-based sorting only
|
metadataFieldValue?: string // relevant to metadata-based group sorting only
|
||||||
|
metadataFieldValueSecondary?: string // relevant to secondary metadata-based sorting only
|
||||||
|
metadataFieldValueForDerived?: string // relevant to metadata-based sorting-spec level sorting only
|
||||||
|
metadataFieldValueForDerivedSecondary?: string // relevant to metadata-based sorting-spec level secondary sorting only
|
||||||
ctime: number // for a file ctime is obvious, for a folder = ctime of the oldest child file
|
ctime: number // for a file ctime is obvious, for a folder = ctime of the oldest child file
|
||||||
mtime: number // for a file mtime is obvious, for a folder = date of most recently modified child file
|
mtime: number // for a file mtime is obvious, for a folder = date of most recently modified child file
|
||||||
isFolder: boolean
|
isFolder: boolean
|
||||||
|
@ -67,6 +70,15 @@ export interface FolderItemForSorting {
|
||||||
bookmarkedIdx?: number // derived from Bookmarks core plugin position
|
bookmarkedIdx?: number // derived from Bookmarks core plugin position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SortingLevelId {
|
||||||
|
forPrimary,
|
||||||
|
forSecondary,
|
||||||
|
forDerivedPrimary,
|
||||||
|
forDerivedSecondary,
|
||||||
|
forUISelected,
|
||||||
|
forLastResort
|
||||||
|
}
|
||||||
|
|
||||||
export type SorterFn = (a: FolderItemForSorting, b: FolderItemForSorting) => number
|
export type SorterFn = (a: FolderItemForSorting, b: FolderItemForSorting) => number
|
||||||
export type PlainSorterFn = (a: TAbstractFile, b: TAbstractFile) => number
|
export type PlainSorterFn = (a: TAbstractFile, b: TAbstractFile) => number
|
||||||
export type PlainFileOnlySorterFn = (a: TFile, b: TFile) => number
|
export type PlainFileOnlySorterFn = (a: TFile, b: TFile) => number
|
||||||
|
@ -79,19 +91,30 @@ const StraightOrder: boolean = false
|
||||||
|
|
||||||
export const EQUAL_OR_UNCOMPARABLE: number = 0
|
export const EQUAL_OR_UNCOMPARABLE: number = 0
|
||||||
|
|
||||||
export const sorterByMetadataField:(reverseOrder?: boolean, trueAlphabetical?: boolean) => SorterFn = (reverseOrder: boolean, trueAlphabetical?: boolean) => {
|
export const getMdata = (it: FolderItemForSorting, mdataId?: SortingLevelId) => {
|
||||||
|
switch (mdataId) {
|
||||||
|
case SortingLevelId.forSecondary: return it.metadataFieldValueSecondary
|
||||||
|
case SortingLevelId.forDerivedPrimary: return it.metadataFieldValueForDerived
|
||||||
|
case SortingLevelId.forDerivedSecondary: return it.metadataFieldValueForDerivedSecondary
|
||||||
|
case SortingLevelId.forPrimary:
|
||||||
|
default: return it.metadataFieldValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sorterByMetadataField = (reverseOrder?: boolean, trueAlphabetical?: boolean, sortLevelId?: SortingLevelId): SorterFn => {
|
||||||
const collatorCompareFn: CollatorCompareFn = trueAlphabetical ? CollatorTrueAlphabeticalCompare : CollatorCompare
|
const collatorCompareFn: CollatorCompareFn = trueAlphabetical ? CollatorTrueAlphabeticalCompare : CollatorCompare
|
||||||
return (a: FolderItemForSorting, b: FolderItemForSorting) => {
|
return (a: FolderItemForSorting, b: FolderItemForSorting) => {
|
||||||
|
let [amdata, bmdata] = [getMdata(a, sortLevelId), getMdata(b, sortLevelId)]
|
||||||
if (reverseOrder) {
|
if (reverseOrder) {
|
||||||
[a, b] = [b, a]
|
[amdata, bmdata] = [bmdata, amdata]
|
||||||
}
|
}
|
||||||
if (a.metadataFieldValue && b.metadataFieldValue) {
|
if (amdata && bmdata) {
|
||||||
const sortResult: number = collatorCompareFn(a.metadataFieldValue, b.metadataFieldValue)
|
const sortResult: number = collatorCompareFn(amdata, bmdata)
|
||||||
return sortResult
|
return sortResult
|
||||||
}
|
}
|
||||||
// Item with metadata goes before the w/o metadata
|
// Item with metadata goes before the w/o metadata
|
||||||
if (a.metadataFieldValue) return -1
|
if (amdata) return -1
|
||||||
if (b.metadataFieldValue) return 1
|
if (bmdata) return 1
|
||||||
|
|
||||||
return EQUAL_OR_UNCOMPARABLE
|
return EQUAL_OR_UNCOMPARABLE
|
||||||
}
|
}
|
||||||
|
@ -127,10 +150,10 @@ let Sorters: { [key in CustomSortOrder]: SorterFn } = {
|
||||||
[CustomSortOrder.byCreatedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctime - b.ctime,
|
[CustomSortOrder.byCreatedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.ctime - b.ctime,
|
||||||
[CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (b.ctime - a.ctime),
|
[CustomSortOrder.byCreatedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? CollatorCompare(a.sortString, b.sortString) : (b.ctime - a.ctime),
|
||||||
[CustomSortOrder.byCreatedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctime - a.ctime,
|
[CustomSortOrder.byCreatedTimeReverseAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => b.ctime - a.ctime,
|
||||||
[CustomSortOrder.byMetadataFieldAlphabetical]: sorterByMetadataField(StraightOrder),
|
[CustomSortOrder.byMetadataFieldAlphabetical]: sorterByMetadataField(StraightOrder, !TrueAlphabetical, SortingLevelId.forPrimary),
|
||||||
[CustomSortOrder.byMetadataFieldTrueAlphabetical]: sorterByMetadataField(StraightOrder, TrueAlphabetical),
|
[CustomSortOrder.byMetadataFieldTrueAlphabetical]: sorterByMetadataField(StraightOrder, TrueAlphabetical, SortingLevelId.forPrimary),
|
||||||
[CustomSortOrder.byMetadataFieldAlphabeticalReverse]: sorterByMetadataField(ReverseOrder),
|
[CustomSortOrder.byMetadataFieldAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, !TrueAlphabetical, SortingLevelId.forPrimary),
|
||||||
[CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, TrueAlphabetical),
|
[CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, TrueAlphabetical, SortingLevelId.forPrimary),
|
||||||
[CustomSortOrder.byBookmarkOrder]: sorterByBookmarkOrder(StraightOrder),
|
[CustomSortOrder.byBookmarkOrder]: sorterByBookmarkOrder(StraightOrder),
|
||||||
[CustomSortOrder.byBookmarkOrderReverse]: sorterByBookmarkOrder(ReverseOrder),
|
[CustomSortOrder.byBookmarkOrderReverse]: sorterByBookmarkOrder(ReverseOrder),
|
||||||
|
|
||||||
|
@ -138,12 +161,34 @@ let Sorters: { [key in CustomSortOrder]: SorterFn } = {
|
||||||
[CustomSortOrder.standardObsidian]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(a.sortString, b.sortString),
|
[CustomSortOrder.standardObsidian]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorCompare(a.sortString, b.sortString),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Some sorters are different when used in primary vs. secondary sorting order
|
||||||
|
let SortersForSecondary: { [key in CustomSortOrder]?: SorterFn } = {
|
||||||
|
[CustomSortOrder.byMetadataFieldAlphabetical]: sorterByMetadataField(StraightOrder, !TrueAlphabetical, SortingLevelId.forSecondary),
|
||||||
|
[CustomSortOrder.byMetadataFieldTrueAlphabetical]: sorterByMetadataField(StraightOrder, TrueAlphabetical, SortingLevelId.forSecondary),
|
||||||
|
[CustomSortOrder.byMetadataFieldAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, !TrueAlphabetical, SortingLevelId.forSecondary),
|
||||||
|
[CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, TrueAlphabetical, SortingLevelId.forSecondary)
|
||||||
|
};
|
||||||
|
|
||||||
|
let SortersForDerivedPrimary: { [key in CustomSortOrder]?: SorterFn } = {
|
||||||
|
[CustomSortOrder.byMetadataFieldAlphabetical]: sorterByMetadataField(StraightOrder, !TrueAlphabetical, SortingLevelId.forDerivedPrimary),
|
||||||
|
[CustomSortOrder.byMetadataFieldTrueAlphabetical]: sorterByMetadataField(StraightOrder, TrueAlphabetical, SortingLevelId.forDerivedPrimary),
|
||||||
|
[CustomSortOrder.byMetadataFieldAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, !TrueAlphabetical, SortingLevelId.forDerivedPrimary),
|
||||||
|
[CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, TrueAlphabetical, SortingLevelId.forDerivedPrimary)
|
||||||
|
};
|
||||||
|
|
||||||
|
let SortersForDerivedSecondary: { [key in CustomSortOrder]?: SorterFn } = {
|
||||||
|
[CustomSortOrder.byMetadataFieldAlphabetical]: sorterByMetadataField(StraightOrder, !TrueAlphabetical, SortingLevelId.forDerivedSecondary),
|
||||||
|
[CustomSortOrder.byMetadataFieldTrueAlphabetical]: sorterByMetadataField(StraightOrder, TrueAlphabetical, SortingLevelId.forDerivedSecondary),
|
||||||
|
[CustomSortOrder.byMetadataFieldAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, !TrueAlphabetical, SortingLevelId.forDerivedSecondary),
|
||||||
|
[CustomSortOrder.byMetadataFieldTrueAlphabeticalReverse]: sorterByMetadataField(ReverseOrder, TrueAlphabetical, SortingLevelId.forDerivedSecondary)
|
||||||
|
};
|
||||||
|
|
||||||
// OS - Obsidian Sort
|
// OS - Obsidian Sort
|
||||||
const OS_alphabetical = 'alphabetical'
|
const OS_alphabetical = 'alphabetical'
|
||||||
const OS_alphabeticalReverse = 'alphabeticalReverse'
|
const OS_alphabeticalReverse = 'alphabeticalReverse'
|
||||||
const OS_byModifiedTime = 'byModifiedTime'
|
export const OS_byModifiedTime = 'byModifiedTime'
|
||||||
const OS_byModifiedTimeReverse = 'byModifiedTimeReverse'
|
export const OS_byModifiedTimeReverse = 'byModifiedTimeReverse'
|
||||||
const OS_byCreatedTime = 'byCreatedTime'
|
export const OS_byCreatedTime = 'byCreatedTime'
|
||||||
const OS_byCreatedTimeReverse = 'byCreatedTimeReverse'
|
const OS_byCreatedTimeReverse = 'byCreatedTimeReverse'
|
||||||
|
|
||||||
export const ObsidianStandardDefaultSortingName = OS_alphabetical
|
export const ObsidianStandardDefaultSortingName = OS_alphabetical
|
||||||
|
@ -192,29 +237,38 @@ export const StandardPlainObsidianComparator = (order: string): PlainSorterFn =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSorterFnFor = (sorting: CustomSortOrder, currentUIselectedSorting?: string): SorterFn => {
|
export const getSorterFnFor = (sorting: CustomSortOrder, currentUIselectedSorting?: string, sortLevelId?: SortingLevelId): SorterFn => {
|
||||||
if (sorting === CustomSortOrder.standardObsidian) {
|
if (sorting === CustomSortOrder.standardObsidian) {
|
||||||
sorting = StandardObsidianToCustomSort[currentUIselectedSorting ?? 'alphabetical'] ?? CustomSortOrder.alphabetical
|
sorting = StandardObsidianToCustomSort[currentUIselectedSorting ?? 'alphabetical'] ?? CustomSortOrder.alphabetical
|
||||||
return StandardObsidianComparator(sorting)
|
return StandardObsidianComparator(sorting)
|
||||||
} else {
|
} else {
|
||||||
return Sorters[sorting]
|
// Some sorters have to know at which sorting level they are used
|
||||||
|
switch(sortLevelId) {
|
||||||
|
case SortingLevelId.forSecondary: return SortersForSecondary[sorting] ?? Sorters[sorting]
|
||||||
|
case SortingLevelId.forDerivedPrimary: return SortersForDerivedPrimary[sorting] ?? Sorters[sorting]
|
||||||
|
case SortingLevelId.forDerivedSecondary: return SortersForDerivedSecondary[sorting] ?? Sorters[sorting]
|
||||||
|
case SortingLevelId.forPrimary:
|
||||||
|
default: return Sorters[sorting]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getComparator(sortSpec: CustomSortSpec, currentUIselectedSorting?: string): SorterFn {
|
export const getComparator = (sortSpec: CustomSortSpec, currentUIselectedSorting?: string): SorterFn => {
|
||||||
const compareTwoItems = (itA: FolderItemForSorting, itB: FolderItemForSorting) => {
|
const compareTwoItems = (itA: FolderItemForSorting, itB: FolderItemForSorting) => {
|
||||||
if (itA.groupIdx != undefined && itB.groupIdx != undefined) {
|
if (itA.groupIdx != undefined && itB.groupIdx != undefined) {
|
||||||
if (itA.groupIdx === itB.groupIdx) {
|
if (itA.groupIdx === itB.groupIdx) {
|
||||||
const group: CustomSortGroup | undefined = sortSpec.groups[itA.groupIdx]
|
const group: CustomSortGroup | undefined = sortSpec.groups[itA.groupIdx]
|
||||||
const primary: number = group?.order ? getSorterFnFor(group.order, currentUIselectedSorting)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
const primary: number = group?.order ? getSorterFnFor(group.order, currentUIselectedSorting, SortingLevelId.forPrimary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
||||||
if (primary !== EQUAL_OR_UNCOMPARABLE) return primary
|
if (primary !== EQUAL_OR_UNCOMPARABLE) return primary
|
||||||
const secondary: number = group?.secondaryOrder ? getSorterFnFor(group.secondaryOrder, currentUIselectedSorting)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
const secondary: number = group?.secondaryOrder ? getSorterFnFor(group.secondaryOrder, currentUIselectedSorting, SortingLevelId.forSecondary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
||||||
if (secondary !== EQUAL_OR_UNCOMPARABLE) return secondary
|
if (secondary !== EQUAL_OR_UNCOMPARABLE) return secondary
|
||||||
const folderLevel: number = sortSpec.defaultOrder ? getSorterFnFor(sortSpec.defaultOrder, currentUIselectedSorting)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
const folderLevel: number = sortSpec.defaultOrder ? getSorterFnFor(sortSpec.defaultOrder, currentUIselectedSorting, SortingLevelId.forDerivedPrimary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
||||||
if (folderLevel !== EQUAL_OR_UNCOMPARABLE) return folderLevel
|
if (folderLevel !== EQUAL_OR_UNCOMPARABLE) return folderLevel
|
||||||
const uiSelected: number = currentUIselectedSorting ? getSorterFnFor(CustomSortOrder.standardObsidian, currentUIselectedSorting)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
const folderLevelSecondary: number = sortSpec.defaultSecondaryOrder ? getSorterFnFor(sortSpec.defaultSecondaryOrder, currentUIselectedSorting, SortingLevelId.forDerivedSecondary)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
||||||
|
if (folderLevelSecondary !== EQUAL_OR_UNCOMPARABLE) return folderLevelSecondary
|
||||||
|
const uiSelected: number = currentUIselectedSorting ? getSorterFnFor(CustomSortOrder.standardObsidian, currentUIselectedSorting, SortingLevelId.forUISelected)(itA, itB) : EQUAL_OR_UNCOMPARABLE
|
||||||
if (uiSelected !== EQUAL_OR_UNCOMPARABLE) return uiSelected
|
if (uiSelected !== EQUAL_OR_UNCOMPARABLE) return uiSelected
|
||||||
const lastResort: number = getSorterFnFor(CustomSortOrder.default)(itA, itB)
|
const lastResort: number = getSorterFnFor(CustomSortOrder.default, undefined, SortingLevelId.forLastResort)(itA, itB)
|
||||||
return lastResort
|
return lastResort
|
||||||
} else {
|
} else {
|
||||||
return itA.groupIdx - itB.groupIdx;
|
return itA.groupIdx - itB.groupIdx;
|
||||||
|
@ -267,7 +321,7 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus
|
||||||
let determined: boolean = false
|
let determined: boolean = false
|
||||||
let derivedText: string | null | undefined
|
let derivedText: string | null | undefined
|
||||||
let bookmarkedIdx: number | undefined
|
let bookmarkedIdx: number | undefined
|
||||||
let metadataValueToSortBy: string | undefined
|
|
||||||
const aFolder: boolean = isFolder(entry)
|
const aFolder: boolean = isFolder(entry)
|
||||||
const aFile: boolean = !aFolder
|
const aFile: boolean = !aFolder
|
||||||
const entryAsTFile: TFile = entry as TFile
|
const entryAsTFile: TFile = entry as TFile
|
||||||
|
@ -431,39 +485,26 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The not obvious logic of determining the value of metadata field to use its value for sorting
|
let metadataValueToSortBy: string | undefined
|
||||||
// - the sorting spec processor automatically populates the order field of CustomSortingGroup for each group
|
let metadataValueSecondaryToSortBy: string | undefined
|
||||||
// - yet defensive code should assume some default
|
let metadataValueDerivedPrimaryToSortBy: string | undefined
|
||||||
// - if the order in group is by metadata (and only in that case):
|
let metadataValueDerivedSecondaryToSortBy: string | undefined
|
||||||
// - if byMetadata field name is defined for the group -> use it. Done even if value empty or not present.
|
|
||||||
// - else, if byMetadata field name is defined for the Sorting spec (folder level, for all groups) -> use it. Done even if value empty or not present.
|
|
||||||
// - else, if withMetadata field name is defined for the group -> use it. Done even if value empty or not present.
|
|
||||||
// - otherwise, fallback to the default metadata field name (hardcoded in the plugin as 'sort-index-value')
|
|
||||||
|
|
||||||
// TODO: in manual of plugin, in details, explain these nuances. Let readme.md contain only the basic simple example and reference to manual.md section
|
|
||||||
|
|
||||||
if (determined && determinedGroupIdx !== undefined) { // <-- defensive code, maybe too defensive
|
if (determined && determinedGroupIdx !== undefined) { // <-- defensive code, maybe too defensive
|
||||||
const group: CustomSortGroup = spec.groups[determinedGroupIdx];
|
const group: CustomSortGroup = spec.groups[determinedGroupIdx];
|
||||||
if (isByMetadata(group?.order)) {
|
const isPrimaryOrderByMetadata: boolean = isByMetadata(group?.order)
|
||||||
let metadataFieldName: string | undefined = group.byMetadataField
|
const isSecondaryOrderByMetadata: boolean = isByMetadata(group?.secondaryOrder)
|
||||||
if (!metadataFieldName) {
|
const isDerivedPrimaryByMetadata: boolean = isByMetadata(spec.defaultOrder)
|
||||||
if (isByMetadata(spec.defaultOrder)) {
|
const isDerivedSecondaryByMetadata: boolean = isByMetadata(spec.defaultSecondaryOrder)
|
||||||
metadataFieldName = spec.byMetadataField
|
if (isPrimaryOrderByMetadata || isSecondaryOrderByMetadata || isDerivedPrimaryByMetadata || isDerivedSecondaryByMetadata) {
|
||||||
}
|
if (ctx?._mCache) {
|
||||||
}
|
// For folders - scan metadata of 'folder note'
|
||||||
if (!metadataFieldName) {
|
const notePathToScan: string = aFile ? entry.path : `${entry.path}/${entry.name}.md`
|
||||||
metadataFieldName = group.withMetadataFieldName
|
const frontMatterCache: FrontMatterCache | undefined = ctx._mCache.getCache(notePathToScan)?.frontmatter
|
||||||
}
|
if (isPrimaryOrderByMetadata) metadataValueToSortBy = frontMatterCache?.[group?.byMetadataField || group?.withMetadataFieldName || DEFAULT_METADATA_FIELD_FOR_SORTING]
|
||||||
if (!metadataFieldName) {
|
if (isSecondaryOrderByMetadata) metadataValueSecondaryToSortBy = frontMatterCache?.[group?.byMetadataFieldSecondary || group?.withMetadataFieldName || DEFAULT_METADATA_FIELD_FOR_SORTING]
|
||||||
metadataFieldName = DEFAULT_METADATA_FIELD_FOR_SORTING
|
if (isDerivedPrimaryByMetadata) metadataValueDerivedPrimaryToSortBy = frontMatterCache?.[spec.byMetadataField || DEFAULT_METADATA_FIELD_FOR_SORTING]
|
||||||
}
|
if (isDerivedSecondaryByMetadata) metadataValueDerivedSecondaryToSortBy = frontMatterCache?.[spec.byMetadataFieldSecondary || DEFAULT_METADATA_FIELD_FOR_SORTING]
|
||||||
if (metadataFieldName) {
|
|
||||||
if (ctx?._mCache) {
|
|
||||||
// For folders - scan metadata of 'folder note'
|
|
||||||
const notePathToScan: string = aFile ? entry.path : `${entry.path}/${entry.name}.md`
|
|
||||||
const frontMatterCache: FrontMatterCache | undefined = ctx._mCache.getCache(notePathToScan)?.frontmatter
|
|
||||||
metadataValueToSortBy = frontMatterCache?.[metadataFieldName]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,6 +514,9 @@ export const determineSortingGroup = function (entry: TFile | TFolder, spec: Cus
|
||||||
groupIdx: determinedGroupIdx,
|
groupIdx: determinedGroupIdx,
|
||||||
sortString: derivedText ?? entry.name,
|
sortString: derivedText ?? entry.name,
|
||||||
metadataFieldValue: metadataValueToSortBy,
|
metadataFieldValue: metadataValueToSortBy,
|
||||||
|
metadataFieldValueSecondary: metadataValueSecondaryToSortBy,
|
||||||
|
metadataFieldValueForDerived: metadataValueDerivedPrimaryToSortBy,
|
||||||
|
metadataFieldValueForDerivedSecondary: metadataValueDerivedSecondaryToSortBy,
|
||||||
isFolder: aFolder,
|
isFolder: aFolder,
|
||||||
folder: aFolder ? (entry as TFolder) : undefined,
|
folder: aFolder ? (entry as TFolder) : undefined,
|
||||||
path: entry.path,
|
path: entry.path,
|
||||||
|
|
Loading…
Reference in New Issue