Merge branch 'master' into 171-poc-metadata-value-extractors-idea
# Conflicts: # manifest.json # src/custom-sort/matchers.ts # src/test/unit/sorting-spec-processor.spec.ts
This commit is contained in:
commit
c5e463b44c
|
@ -1,5 +1,6 @@
|
|||
> | :exclamation: Breaking changes in Obsidian - always use the newest version of the plugin|
|
||||
> |----------------------------------------------|
|
||||
> | - Obsidian 1.7.2 - no fixes for Obsidian breaking changes available --> [More details](README.notice.for.Obsidian.1.7.2.md)|
|
||||
> | - Obsidian 1.6.3 - update the plugin to 2.1.11 or newer --> [More details](README.notice.for.Obsidian.1.6.3.md)|
|
||||
> | - Obsidian 1.6.0 - update the plugin to 2.1.9 or newer --> [More details](README.notice.for.Obsidian.1.6.0.md)|
|
||||
> | - Obsidian 1.5.4 - update the plugin to 2.1.7 or newer --> [More details](README.notice.for.Obsidian.1.5.4.md)|
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
> | :exclamation: Breaking changes in Obsidian 1.7.2 (and newer) - no fixes available|
|
||||
> |----------------------------------------------|
|
||||
>
|
||||
> Obsidian team introduced some more breaking changes in a not-backward-compatible way starting from Obsidian 1.7.2.
|
||||
>
|
||||
> The observed issues are minor, no fixes available (a work in progress with unknown release date):
|
||||
> - the custom sort plugin is **unable to automatically apply the custom sort on start**
|
||||
> - prevalent on mobile
|
||||
> - for the _Lazy Plugin Loader_ plugin occurs by definition
|
||||
> - **workaround**: custom sorting has to be applied manually via the ribbon icon or the command 'sort on'
|
||||
> - the custom sort plugin **keeps showing the notifications** with each change to any note
|
||||
> - **workaround**: disable the notifications
|
||||
>
|
||||
> For more details of the observed misbehaviors you can go to:
|
||||
> - [#161: Find out how to automatically apply custom sort on app start / vault (re)load etc.](https://github.com/SebastianMC/obsidian-custom-sort/issues/161)
|
||||
> - [#162: \[bug\]\[minor\] Obsidian 1.7.2 breaking changes - when File Explorer is not displayed an attempt to apply custom sort fails with error](https://github.com/SebastianMC/obsidian-custom-sort/issues/162)
|
||||
> - [#163: Obsidian 1.7.2 - automatic sorting fails when launching Obsidian](https://github.com/SebastianMC/obsidian-custom-sort/issues/163)
|
||||
> - [#165: Obsidian 1.7.3 - Constant Notifications "Custom sorting ON" and "Parsing custom sorting specification SUCCEEDED!"](https://github.com/SebastianMC/obsidian-custom-sort/issues/165)
|
||||
> - [#169: Not working on mobile](https://github.com/SebastianMC/obsidian-custom-sort/issues/169)
|
||||
>
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "custom-sort",
|
||||
"name": "Custom File Explorer sorting",
|
||||
"version": "2.1.14-beta-171",
|
||||
"version": "2.1.15-",
|
||||
"minAppVersion": "0.16.2",
|
||||
"description": "Allows for manual and automatic, config-driven reordering and sorting of files and folders in File Explorer",
|
||||
"author": "SebastianMC",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-custom-sort",
|
||||
"version": "2.1.14",
|
||||
"version": "2.1.15",
|
||||
"description": "Custom Sort plugin for Obsidian (https://obsidian.md)",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -241,7 +241,7 @@ const SortersForDerivedSecondary: { [key in CustomSortOrder]?: SorterFn } = {
|
|||
};
|
||||
|
||||
// OS - Obsidian Sort
|
||||
const OS_alphabetical = 'alphabetical'
|
||||
export const OS_alphabetical = 'alphabetical'
|
||||
const OS_alphabeticalReverse = 'alphabeticalReverse'
|
||||
export const OS_byModifiedTime = 'byModifiedTime'
|
||||
export const OS_byModifiedTimeReverse = 'byModifiedTimeReverse'
|
||||
|
@ -812,7 +812,7 @@ const folderSortCore = function (sortedFolder: TFolder, sortOrder: string, sorti
|
|||
};
|
||||
|
||||
// Returns a sorted copy of the input array, intentionally to keep it intact
|
||||
export const sortFolderItemsForBookmarking = function (folder: TFolder, items: Array<TAbstractFile>, sortingSpec: CustomSortSpec|null|undefined, ctx: ProcessingContext, uiSortOrder: string): Array<TAbstractFile> {
|
||||
export const sortFolderItems = function (folder: TFolder, items: Array<TAbstractFile>, sortingSpec: CustomSortSpec|null|undefined, ctx: ProcessingContext, uiSortOrder: string): Array<TAbstractFile> {
|
||||
if (sortingSpec) {
|
||||
const folderItemsByPath: { [key: string]: TAbstractFile } = {}
|
||||
|
||||
|
@ -849,6 +849,9 @@ export const sortFolderItemsForBookmarking = function (folder: TFolder, items: A
|
|||
}
|
||||
};
|
||||
|
||||
// Exported legacy function name for backward compatibility
|
||||
export const sortFolderItemsForBookmarking = sortFolderItems
|
||||
|
||||
export const _unitTests = {
|
||||
fileGoesFirstWhenSameBasenameAsFolder: fileGoesFirstWhenSameBasenameAsFolder,
|
||||
folderGoesFirstWhenSameBasenameAsFolder: folderGoesFirstWhenSameBasenameAsFolder
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import {toString} from "builtin-modules";
|
||||
|
||||
export const RomanNumberRegexStr: string = ' *([MDCLXVI]+)'; // Roman number
|
||||
export const CompoundRomanNumberDotRegexStr: string = ' *([MDCLXVI]+(?:\\.[MDCLXVI]+)*)';// Compound Roman number with dot as separator
|
||||
export const CompoundRomanNumberDashRegexStr: string = ' *([MDCLXVI]+(?:-[MDCLXVI]+)*)'; // Compound Roman number with dash as separator
|
||||
|
@ -9,6 +7,7 @@ export const CompoundNumberDotRegexStr: string = ' *(\\d+(?:\\.\\d+)*)'; // Comp
|
|||
export const CompoundNumberDashRegexStr: string = ' *(\\d+(?:-\\d+)*)'; // Compound number with dash as separator
|
||||
|
||||
export const Date_dd_Mmm_yyyy_RegexStr: string = ' *([0-3]*[0-9]-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\\d{4})'; // Date like 01-Jan-2020
|
||||
export const Date_Mmm_dd_yyyy_RegexStr: string = ' *((?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-[0-3]*[0-9]-\\d{4})'; // Date like Jan-01-2020
|
||||
|
||||
export const DOT_SEPARATOR = '.'
|
||||
export const DASH_SEPARATOR = '-'
|
||||
|
@ -123,16 +122,4 @@ export function getNormalizedDate_NormalizerFn_for(separator: string, dayIdx: nu
|
|||
}
|
||||
|
||||
export const getNormalizedDate_dd_Mmm_yyyy_NormalizerFn = getNormalizedDate_NormalizerFn_for('-', 0, 1, 2, MONTHS)
|
||||
|
||||
/*
|
||||
// Assumption - the regex date matched against input s, no extensive defensive coding needed
|
||||
const components = s.split('-')
|
||||
const day = prependWithZeros(components[0], DAY_POSITIONS)
|
||||
const month = prependWithZeros( `${1 + MONTHS.indexOf(components[1])}`, MONTH_POSITIONS)
|
||||
const year = prependWithZeros(components[2], YEAR_POSITIONS)
|
||||
return `${year}-${month}-${day}//`
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
export const getNormalizedDate_Mmm_dd_yyyy_NormalizerFn = getNormalizedDate_NormalizerFn_for('-', 1, 0, 2, MONTHS)
|
||||
|
|
|
@ -17,8 +17,10 @@ import {
|
|||
CompoundRomanNumberDotRegexStr,
|
||||
DASH_SEPARATOR,
|
||||
Date_dd_Mmm_yyyy_RegexStr,
|
||||
Date_Mmm_dd_yyyy_RegexStr,
|
||||
DOT_SEPARATOR,
|
||||
getNormalizedDate_dd_Mmm_yyyy_NormalizerFn,
|
||||
getNormalizedDate_Mmm_dd_yyyy_NormalizerFn,
|
||||
getNormalizedNumber,
|
||||
getNormalizedRomanNumber,
|
||||
NumberRegexStr,
|
||||
|
@ -358,6 +360,7 @@ const InlineRegexSymbol_Digit2: string = '\\[0-9]'
|
|||
const InlineRegexSymbol_0_to_3: string = '\\[0-3]'
|
||||
|
||||
const Date_dd_Mmm_yyyy_RegexSymbol: string = '\\[dd-Mmm-yyyy]'
|
||||
const Date_Mmm_dd_yyyy_RegexSymbol: string = '\\[Mmm-dd-yyyy]'
|
||||
|
||||
const InlineRegexSymbol_CapitalLetter: string = '\\C'
|
||||
const InlineRegexSymbol_LowercaseLetter: string = '\\l'
|
||||
|
@ -377,7 +380,8 @@ const sortingSymbolsArr: Array<string> = [
|
|||
escapeRegexUnsafeCharacters(CompoundRomanNumberDashRegexSymbol),
|
||||
escapeRegexUnsafeCharacters(WordInASCIIRegexSymbol),
|
||||
escapeRegexUnsafeCharacters(WordInAnyLanguageRegexSymbol),
|
||||
escapeRegexUnsafeCharacters(Date_dd_Mmm_yyyy_RegexSymbol)
|
||||
escapeRegexUnsafeCharacters(Date_dd_Mmm_yyyy_RegexSymbol),
|
||||
escapeRegexUnsafeCharacters(Date_Mmm_dd_yyyy_RegexSymbol)
|
||||
]
|
||||
|
||||
const sortingSymbolsRegex = new RegExp(sortingSymbolsArr.join('|'), 'gi')
|
||||
|
@ -446,6 +450,7 @@ export const NumberNormalizerFn: NormalizerFn = (s: string) => getNormalizedNumb
|
|||
export const CompoundDotNumberNormalizerFn: NormalizerFn = (s: string) => getNormalizedNumber(s, DOT_SEPARATOR)
|
||||
export const CompoundDashNumberNormalizerFn: NormalizerFn = (s: string) => getNormalizedNumber(s, DASH_SEPARATOR)
|
||||
export const Date_dd_Mmm_yyyy_NormalizerFn: NormalizerFn = (s: string) => getNormalizedDate_dd_Mmm_yyyy_NormalizerFn(s)
|
||||
export const Date_Mmm_dd_yyyy_NormalizerFn: NormalizerFn = (s: string) => getNormalizedDate_Mmm_dd_yyyy_NormalizerFn(s)
|
||||
|
||||
export enum AdvancedRegexType {
|
||||
None, // to allow if (advancedRegex)
|
||||
|
@ -457,7 +462,8 @@ export enum AdvancedRegexType {
|
|||
CompoundDashRomanNumber,
|
||||
WordInASCII,
|
||||
WordInAnyLanguage,
|
||||
Date_dd_Mmm_yyyy
|
||||
Date_dd_Mmm_yyyy,
|
||||
Date_Mmm_dd_yyyy
|
||||
}
|
||||
|
||||
const sortingSymbolToRegexpStr: { [key: string]: RegExpSpecStr } = {
|
||||
|
@ -506,6 +512,11 @@ const sortingSymbolToRegexpStr: { [key: string]: RegExpSpecStr } = {
|
|||
regexpStr: Date_dd_Mmm_yyyy_RegexStr,
|
||||
normalizerFn: Date_dd_Mmm_yyyy_NormalizerFn,
|
||||
advancedRegexType: AdvancedRegexType.Date_dd_Mmm_yyyy
|
||||
},
|
||||
[Date_Mmm_dd_yyyy_RegexSymbol]: { // Intentionally retain character case
|
||||
regexpStr: Date_Mmm_dd_yyyy_RegexStr,
|
||||
normalizerFn: Date_Mmm_dd_yyyy_NormalizerFn,
|
||||
advancedRegexType: AdvancedRegexType.Date_Mmm_dd_yyyy
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import {
|
||||
TAbstractFile,
|
||||
TFolder,
|
||||
Vault
|
||||
} from "obsidian";
|
||||
import {
|
||||
DEFAULT_FOLDER_CTIME,
|
||||
determineFolderDatesIfNeeded,
|
||||
determineSortingGroup,
|
||||
FolderItemForSorting, OS_alphabetical, OS_byCreatedTime, ProcessingContext, sortFolderItems
|
||||
} from "../../custom-sort/custom-sort";
|
||||
import {
|
||||
CustomSortGroupType,
|
||||
CustomSortOrder,
|
||||
CustomSortSpec
|
||||
} from "../../custom-sort/custom-sort-types";
|
||||
import {
|
||||
TIMESTAMP_OLDEST,
|
||||
TIMESTAMP_NEWEST,
|
||||
mockTFolderWithChildren,
|
||||
mockTFolderWithDateNamedChildren,
|
||||
TIMESTAMP_DEEP_NEWEST,
|
||||
TIMESTAMP_DEEP_OLDEST,
|
||||
} from "../mocks";
|
||||
import {
|
||||
SortingSpecProcessor
|
||||
} from "../../custom-sort/sorting-spec-processor";
|
||||
|
||||
describe('sortFolderItems', () => {
|
||||
it('should correctly handle Mmm-dd-yyyy pattern in file names', () => {
|
||||
// given
|
||||
const processor: SortingSpecProcessor = new SortingSpecProcessor()
|
||||
const sortSpecTxt =
|
||||
` ... \\[Mmm-dd-yyyy]
|
||||
> a-z
|
||||
`
|
||||
const PARENT_PATH = 'parent/folder/path'
|
||||
const sortSpecsCollection = processor.parseSortSpecFromText(
|
||||
sortSpecTxt.split('\n'),
|
||||
PARENT_PATH,
|
||||
'file name with the sorting, irrelevant here'
|
||||
)
|
||||
|
||||
const folder: TFolder = mockTFolderWithDateNamedChildren(PARENT_PATH)
|
||||
const sortSpec: CustomSortSpec = sortSpecsCollection?.sortSpecByPath![PARENT_PATH]!
|
||||
|
||||
const ctx: ProcessingContext = {}
|
||||
|
||||
// when
|
||||
const result: Array<TAbstractFile> = sortFolderItems(folder, folder.children, sortSpec, ctx, OS_alphabetical)
|
||||
|
||||
// then
|
||||
const orderedNames = result.map(f => f.name)
|
||||
expect(orderedNames).toEqual([
|
||||
'CCC Feb-28-2025',
|
||||
'BBB Dec-23-2024.md',
|
||||
'DDD Jul-15-2024.md',
|
||||
'AAA Jan-01-2012'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -3,6 +3,9 @@ import {
|
|||
TFolder,
|
||||
Vault
|
||||
} from "obsidian";
|
||||
import {
|
||||
lastPathComponent
|
||||
} from "../utils/utils";
|
||||
|
||||
export const mockTFile = (basename: string, ext: string, size?: number, ctime?: number, mtime?: number): TFile => {
|
||||
return {
|
||||
|
@ -25,7 +28,7 @@ export const mockTFolder = (name: string, children?: Array<TFolder|TFile>, paren
|
|||
isRoot(): boolean { return name === '/' },
|
||||
vault: {} as Vault, // To satisfy TS typechecking
|
||||
path: `${name}`,
|
||||
name: name,
|
||||
name: lastPathComponent(name),
|
||||
parent: parent ?? ({} as TFolder), // To satisfy TS typechecking
|
||||
children: children ?? []
|
||||
}
|
||||
|
@ -53,3 +56,12 @@ export const mockTFolderWithChildren = (name: string): TFolder => {
|
|||
|
||||
return mockTFolder(name, [child1, child2, child3, child4, child5, subfolder1, subfolder2])
|
||||
}
|
||||
|
||||
export const mockTFolderWithDateNamedChildren = (name: string): TFolder => {
|
||||
const child1: TFolder = mockTFolder('AAA Jan-01-2012')
|
||||
const child2: TFile = mockTFile('BBB Dec-23-2024', 'md')
|
||||
const child3: TFolder = mockTFolder('CCC Feb-28-2025')
|
||||
const child4: TFile = mockTFile('DDD Jul-15-2024', 'md')
|
||||
|
||||
return mockTFolder(name, [child1, child2, child3, child4])
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
consumeFolderByRegexpExpression,
|
||||
convertPlainStringToRegex,
|
||||
Date_dd_Mmm_yyyy_NormalizerFn,
|
||||
Date_Mmm_dd_yyyy_NormalizerFn,
|
||||
detectSortingSymbols,
|
||||
escapeRegexUnsafeCharacters,
|
||||
extractSortingSymbol,
|
||||
|
@ -363,17 +364,6 @@ const expectedSortSpecsExampleA: { [key: string]: CustomSortSpec } = {
|
|||
}
|
||||
}
|
||||
|
||||
const txtInputExampleSortingSymbols: string = `
|
||||
/folders Chapter \\.d+ ...
|
||||
/:files ...section \\-r+.
|
||||
% Appendix \\-d+ (attachments)
|
||||
Plain syntax\\R+ ... works?
|
||||
And this kind of... \\D+plain syntax???
|
||||
Here goes ASCII word \\a+
|
||||
\\A+. is for any modern language word
|
||||
\\[dd-Mmm-yyyy] for the specific date format of 12-Apr-2024
|
||||
`
|
||||
|
||||
const expectedSortSpecsExampleSortingSymbols: { [key: string]: CustomSortSpec } = {
|
||||
"mock-folder": {
|
||||
groups: [{
|
||||
|
@ -428,14 +418,32 @@ const expectedSortSpecsExampleSortingSymbols: { [key: string]: CustomSortSpec }
|
|||
regex: /^ *([0-3]*[0-9]-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d{4}) for the specific date format of 12\-Apr\-2024$/i,
|
||||
normalizerFn: Date_dd_Mmm_yyyy_NormalizerFn
|
||||
}
|
||||
}, {
|
||||
type: CustomSortGroupType.ExactName,
|
||||
regexPrefix: {
|
||||
regex: /^ *((?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-[0-3]*[0-9]-\d{4}) for the specific date format of Apr\-01\-2024$/i,
|
||||
normalizerFn: Date_Mmm_dd_yyyy_NormalizerFn
|
||||
}
|
||||
}, {
|
||||
type: CustomSortGroupType.Outsiders
|
||||
}],
|
||||
targetFoldersPaths: ['mock-folder'],
|
||||
outsidersGroupIdx: 8
|
||||
outsidersGroupIdx: 9
|
||||
}
|
||||
}
|
||||
|
||||
const txtInputExampleSortingSymbols: string = `
|
||||
/folders Chapter \\.d+ ...
|
||||
/:files ...section \\-r+.
|
||||
% Appendix \\-d+ (attachments)
|
||||
Plain syntax\\R+ ... works?
|
||||
And this kind of... \\D+plain syntax???
|
||||
Here goes ASCII word \\a+
|
||||
\\A+. is for any modern language word
|
||||
\\[dd-Mmm-yyyy] for the specific date format of 12-Apr-2024
|
||||
\\[Mmm-dd-yyyy] for the specific date format of Apr-01-2024
|
||||
`
|
||||
|
||||
const txtInputExampleMDataExtractors1: string = `
|
||||
< a-z by-metadata: created-by using-extractor: date(dd/mm/yyyy)
|
||||
/folders Chapter...
|
||||
|
|
|
@ -47,5 +47,6 @@
|
|||
"2.1.11": "0.16.2",
|
||||
"2.1.12": "0.16.2",
|
||||
"2.1.13": "0.16.2",
|
||||
"2.1.14": "0.16.2"
|
||||
"2.1.14": "0.16.2",
|
||||
"2.1.15": "0.16.2"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue