Skip to content

Commit fa6aafa

Browse files
authored
Merge pull request #152 from SebastianMC/151-sort-notes-in-dd-mmm-yyyy-format
151 sort notes in dd mmm yyyy format
2 parents 0ac058b + 16b50c3 commit fa6aafa

File tree

4 files changed

+79
-10
lines changed

4 files changed

+79
-10
lines changed

src/custom-sort/matchers.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {toString} from "builtin-modules";
2+
13
export const RomanNumberRegexStr: string = ' *([MDCLXVI]+)'; // Roman number
24
export const CompoundRomanNumberDotRegexStr: string = ' *([MDCLXVI]+(?:\\.[MDCLXVI]+)*)';// Compound Roman number with dot as separator
35
export const CompoundRomanNumberDashRegexStr: string = ' *([MDCLXVI]+(?:-[MDCLXVI]+)*)'; // Compound Roman number with dash as separator
@@ -6,6 +8,8 @@ export const NumberRegexStr: string = ' *(\\d+)'; // Plain number
68
export const CompoundNumberDotRegexStr: string = ' *(\\d+(?:\\.\\d+)*)'; // Compound number with dot as separator
79
export const CompoundNumberDashRegexStr: string = ' *(\\d+(?:-\\d+)*)'; // Compound number with dash as separator
810

11+
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
12+
913
export const DOT_SEPARATOR = '.'
1014
export const DASH_SEPARATOR = '-'
1115

@@ -23,12 +27,16 @@ export const WordInAnyLanguageRegexStr = '(\\p{Letter}+)' // remember about th
2327

2428
export const WordInASCIIRegexStr = '([a-zA-Z]+)'
2529

26-
export function prependWithZeros(s: string, minLength: number) {
27-
if (s.length < minLength) {
28-
const delta: number = minLength - s.length;
29-
return '000000000000000000000000000'.substring(0, delta) + s;
30+
export function prependWithZeros(s: string|undefined, minLength: number): string {
31+
if ('string' === typeof s) {
32+
if (s.length < minLength) {
33+
const delta: number = minLength - s.length;
34+
return '000000000000000000000000000'.substring(0, delta) + s;
35+
} else {
36+
return s;
37+
}
3038
} else {
31-
return s;
39+
return prependWithZeros((s ?? '').toString(), minLength)
3240
}
3341
}
3442

@@ -95,3 +103,18 @@ export function getNormalizedRomanNumber(s: string, separator?: string, places?:
95103
return `${prependWithZeros(romanToIntStr(s), places ?? DEFAULT_NORMALIZATION_PLACES)}//`
96104
}
97105
}
106+
107+
const DAY_POSITIONS = '00'.length
108+
const MONTH_POSITIONS = '00'.length
109+
const YEAR_POSITIONS = '0000'.length
110+
111+
const MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
112+
113+
export function getNormalizedDate_dd_Mmm_yyyy_NormalizerFn(s: string): string | null {
114+
// Assumption - the regex date matched against input s, no extensive defensive coding needed
115+
const components = s.split('-')
116+
const day = prependWithZeros(components[0], DAY_POSITIONS)
117+
const month = prependWithZeros( `${1 + MONTHS.indexOf(components[1])}`, MONTH_POSITIONS)
118+
const year = prependWithZeros(components[2], YEAR_POSITIONS)
119+
return `${year}-${month}-${day}//`
120+
}

src/custom-sort/sorting-spec-processor.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import {
1616
CompoundRomanNumberDashRegexStr,
1717
CompoundRomanNumberDotRegexStr,
1818
DASH_SEPARATOR,
19+
Date_dd_Mmm_yyyy_RegexStr,
1920
DOT_SEPARATOR,
21+
getNormalizedDate_dd_Mmm_yyyy_NormalizerFn,
2022
getNormalizedNumber,
2123
getNormalizedRomanNumber,
2224
NumberRegexStr,
@@ -348,6 +350,8 @@ const InlineRegexSymbol_Digit1: string = '\\d'
348350
const InlineRegexSymbol_Digit2: string = '\\[0-9]'
349351
const InlineRegexSymbol_0_to_3: string = '\\[0-3]'
350352

353+
const Date_dd_Mmm_yyyy_RegexSymbol: string = '\\[dd-Mmm-yyyy]'
354+
351355
const InlineRegexSymbol_CapitalLetter: string = '\\C'
352356
const InlineRegexSymbol_LowercaseLetter: string = '\\l'
353357

@@ -365,7 +369,8 @@ const sortingSymbolsArr: Array<string> = [
365369
escapeRegexUnsafeCharacters(CompoundRomanNumberDotRegexSymbol),
366370
escapeRegexUnsafeCharacters(CompoundRomanNumberDashRegexSymbol),
367371
escapeRegexUnsafeCharacters(WordInASCIIRegexSymbol),
368-
escapeRegexUnsafeCharacters(WordInAnyLanguageRegexSymbol)
372+
escapeRegexUnsafeCharacters(WordInAnyLanguageRegexSymbol),
373+
escapeRegexUnsafeCharacters(Date_dd_Mmm_yyyy_RegexSymbol)
369374
]
370375

371376
const sortingSymbolsRegex = new RegExp(sortingSymbolsArr.join('|'), 'gi')
@@ -433,6 +438,7 @@ export const CompoundDashRomanNumberNormalizerFn: NormalizerFn = (s: string) =>
433438
export const NumberNormalizerFn: NormalizerFn = (s: string) => getNormalizedNumber(s)
434439
export const CompoundDotNumberNormalizerFn: NormalizerFn = (s: string) => getNormalizedNumber(s, DOT_SEPARATOR)
435440
export const CompoundDashNumberNormalizerFn: NormalizerFn = (s: string) => getNormalizedNumber(s, DASH_SEPARATOR)
441+
export const Date_dd_Mmm_yyyy_NormalizerFn: NormalizerFn = (s: string) => getNormalizedDate_dd_Mmm_yyyy_NormalizerFn(s)
436442

437443
export enum AdvancedRegexType {
438444
None, // to allow if (advancedRegex)
@@ -443,7 +449,8 @@ export enum AdvancedRegexType {
443449
CompoundDotRomanNumber,
444450
CompoundDashRomanNumber,
445451
WordInASCII,
446-
WordInAnyLanguage
452+
WordInAnyLanguage,
453+
Date_dd_Mmm_yyyy
447454
}
448455

449456
const sortingSymbolToRegexpStr: { [key: string]: RegExpSpecStr } = {
@@ -487,6 +494,11 @@ const sortingSymbolToRegexpStr: { [key: string]: RegExpSpecStr } = {
487494
normalizerFn: IdentityNormalizerFn,
488495
advancedRegexType: AdvancedRegexType.WordInAnyLanguage,
489496
unicodeRegex: true
497+
},
498+
[Date_dd_Mmm_yyyy_RegexSymbol]: { // Intentionally retain character case
499+
regexpStr: Date_dd_Mmm_yyyy_RegexStr,
500+
normalizerFn: Date_dd_Mmm_yyyy_NormalizerFn,
501+
advancedRegexType: AdvancedRegexType.Date_dd_Mmm_yyyy
490502
}
491503
}
492504

src/test/unit/matchers.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
CompoundRomanNumberDotRegexStr,
1111
CompoundRomanNumberDashRegexStr,
1212
WordInASCIIRegexStr,
13-
WordInAnyLanguageRegexStr
13+
WordInAnyLanguageRegexStr, getNormalizedDate_dd_Mmm_yyyy_NormalizerFn
1414
} from "../../custom-sort/matchers";
1515

1616
describe('Plain numbers regexp', () => {
@@ -405,3 +405,29 @@ describe('getNormalizedRomanNumber', () => {
405405
expect(getNormalizedRomanNumber(s, separator, LEN)).toBe(out)
406406
})
407407
})
408+
409+
describe('getNormalizedDate_dd_Mmm_yyyy_NormalizerFn', () => {
410+
const params = [
411+
['13-Jan-2012', '2012-01-13//'],
412+
['3-Feb-2', '0002-02-03//'],
413+
['1-Mar-1900', '1900-03-01//'],
414+
['42-Apr-9999', '9999-04-42//'],
415+
['0-May-0', '0000-05-00//'],
416+
['21-Jun-2024', '2024-06-21//'],
417+
['7-Jul-1872', '1872-07-07//'],
418+
['15-Aug-1234', '1234-08-15//'],
419+
['1234-Sep-7777', '7777-09-1234//'],
420+
['3-Oct-2023', '2023-10-03//'],
421+
['8-Nov-2022', '2022-11-08//'],
422+
['18-Dec-2021', '2021-12-18//'],
423+
['88-Dec-2012', '2012-12-88//'], // Invalid case, Regexp on matcher in the caller should guard against this
424+
['13-JANUARY-2012', '2012-00-13//'], // Invalid case, Regexp on matcher in the caller should guard against this
425+
['1 .1', '0000-00-1 .1//'], // Invalid case, Regexp on matcher in the caller should guard against this
426+
['', '0000-00-00//'], // Invalid case, Regexp on matcher in the caller should guard against this
427+
['abc', '0000-00-abc//'], // Invalid case, Regexp on matcher in the caller should guard against this
428+
['def-abc', '0000-00-def//'], // Invalid case, Regexp on matcher in the caller should guard against this
429+
];
430+
it.each(params)('>%s< should become %s', (s: string, out: string) => {
431+
expect(getNormalizedDate_dd_Mmm_yyyy_NormalizerFn(s)).toBe(out)
432+
})
433+
})

src/test/unit/sorting-spec-processor.spec.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
CompoundDotNumberNormalizerFn,
55
ConsumedFolderMatchingRegexp,
66
consumeFolderByRegexpExpression,
7-
convertPlainStringToRegex,
7+
convertPlainStringToRegex, Date_dd_Mmm_yyyy_NormalizerFn,
88
detectSortingSymbols,
99
escapeRegexUnsafeCharacters,
1010
extractSortingSymbol,
@@ -404,11 +404,17 @@ const expectedSortSpecsExampleSortingSymbols: { [key: string]: CustomSortSpec }
404404
regex: /^(\p{Letter}+)\. is for any modern language word$/iu,
405405
normalizerFn: IdentityNormalizerFn
406406
}
407+
}, {
408+
type: CustomSortGroupType.ExactName,
409+
regexPrefix: {
410+
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,
411+
normalizerFn: Date_dd_Mmm_yyyy_NormalizerFn
412+
}
407413
}, {
408414
type: CustomSortGroupType.Outsiders
409415
}],
410416
targetFoldersPaths: ['mock-folder'],
411-
outsidersGroupIdx: 7
417+
outsidersGroupIdx: 8
412418
}
413419
}
414420

@@ -420,6 +426,7 @@ Plain syntax\\R+ ... works?
420426
And this kind of... \\D+plain syntax???
421427
Here goes ASCII word \\a+
422428
\\A+. is for any modern language word
429+
\\[dd-Mmm-yyyy] for the specific date format of 12-Apr-2024
423430
`
424431

425432
describe('SortingSpecProcessor', () => {
@@ -3141,6 +3148,7 @@ describe('hasMoreThanOneSortingSymbol', () => {
31413148
['\\-r+', false], ['--\\-r+--\\-D+++', true],
31423149
['\\d+abcd\\d+efgh', true],
31433150
['\\R+abcd\\.R+efgh', true],
3151+
['\\R+abcd\\[dd-Mmm-yyyy]', true],
31443152
['\\d+\\.D+\\-d+\\R+\\.r+\\-R+ \\d+', true]
31453153
])('should correctly detect in >%s< (%s) sorting regex symbols', (s: string, b: boolean) => {
31463154
const result = hasMoreThanOneSortingSymbol(s)

0 commit comments

Comments
 (0)